{"id":1099,"date":"2026-07-31T23:15:46","date_gmt":"2026-07-31T20:15:46","guid":{"rendered":"https:\/\/news.tfeya.ru\/?p=1099"},"modified":"2026-07-31T23:29:55","modified_gmt":"2026-07-31T20:29:55","slug":"%d0%bd%d0%b5-%d0%b2%d1%8b%d0%b1%d0%b8%d1%80%d0%b0%d0%b9%d1%82%d0%b5-%d0%bc%d0%b5%d0%b6%d0%b4%d1%83-%d1%8f%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%be%d0%bc-%d0%b8-diy-%d0%ba%d0%b0%d0%ba-%d0%bd%d0%b0%d0%bf","status":"publish","type":"post","link":"https:\/\/news.tfeya.ru\/?p=1099","title":{"rendered":"\u041d\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0439\u0442\u0435 \u043c\u0435\u0436\u0434\u0443 \u042f\u043d\u0434\u0435\u043a\u0441\u043e\u043c \u0438 DIY: \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u00ab\u043c\u043e\u0441\u0442\u00bb \u0434\u043b\u044f \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u043d\u0430 PHP \u0437\u0430 \u0432\u0435\u0447\u0435\u0440"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>\u0418\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0433\u0438\u0431\u0440\u0438\u0434\u043d\u044b\u0439 \u0443\u043c\u043d\u044b\u0439 \u0434\u043e\u043c \u2014 \u044d\u0442\u043e \u043d\u0435 \u00ab\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u0435 \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430\u00bb, \u0430 \u0430\u043f\u0433\u0440\u0435\u0439\u0434 \u0435\u0433\u043e \u0434\u043e \u0432\u043d\u0435\u0434\u043e\u0440\u043e\u0436\u043d\u0438\u043a\u0430.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u0438\u0441\u043f\u043b\u0435\u0439, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043e\u0442 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0438\u043b\u0438 \u0421\u0431\u0435\u0440\u0430, \u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0447\u0435\u0440\u0435\u0437 API \u0441\u0447\u0438\u0442\u0430\u043d\u044b \u0443\u043c\u043d\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u044b \u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u0432\u043a\u043b \/ \u0432\u044b\u043a\u043b). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0415\u0441\u043b\u0438 \u043f\u0440\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0441 \u0410\u043b\u0438\u0441\u043e\u0439 \u043d\u0443\u0436\u043d\u043e \u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c, \u043d\u0430\u0437\u0432\u0430\u043d \u043b\u0438 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440\u043e\u043c \u0438\u043b\u0438 \u0436\u0435 \u043d\u0430\u0434\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0442\u043e\u0447\u043d\u043e &#171;\u0442\u0435\u043b\u0435\u0432\u0438\u0437\u043e\u0440 \u0432 \u0437\u0430\u043b\u0435&#187;&#8230; \u0422\u043e \u043d\u0430 \u0445\u043e\u043b\u043e\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0435 \u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043c\u043e\u0436\u043d\u043e \u0447\u0435\u0442\u043a\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0441\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u2013 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u043d\u0443\u0442\u044c \u043f\u043e\u043b\u0437\u0443\u043d\u043e\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432, \u0447\u0442\u043e\u0431\u044b \u0438\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0441\u0442\u0430\u0442\u044c\u044f \u043e \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u0442\u0447\u0438\u043a\u0430\u0445 \u043d\u0430 ESP8266 \u0438\u043b\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430, \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0432\u043e\u043f\u0440\u043e\u0441:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><em>\u00ab\u0417\u0430\u0447\u0435\u043c \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u044c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434? \u0415\u0441\u0442\u044c \u0436\u0435 \u042f\u043d\u0434\u0435\u043a\u0441 \u0441 \u0410\u043b\u0438\u0441\u043e\u0439, \u0421\u0431\u0435\u0440, Tuya. \u041a\u0443\u043f\u0438\u043b \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u0440\u043e\u0437\u0435\u0442\u043a\u0443 \u0437\u0430 500 \u0440\u0443\u0431\u043b\u0435\u0439, \u0438 \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041a\u0430\u043a \u0432\u044b \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u043e\u0434\u0435\u043b\u043a\u0438 \u0432 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b?\u00bb<\/em><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412\u043e\u043f\u0440\u043e\u0441 \u0441\u043f\u0440\u0430\u0432\u0435\u0434\u043b\u0438\u0432\u044b\u0439. \u041d\u043e \u043e\u043d \u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 \u043b\u043e\u0436\u043d\u043e\u0439 \u0434\u0438\u0445\u043e\u0442\u043e\u043c\u0438\u0438: \u0431\u0443\u0434\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c&nbsp;<em>\u043b\u0438\u0431\u043e<\/em>&nbsp;\u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0435 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b,&nbsp;<em>\u043b\u0438\u0431\u043e<\/em>&nbsp;\u0441\u0432\u043e\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0441\u0430\u043c\u0430\u044f \u043c\u043e\u0449\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u2014&nbsp;<strong>\u0433\u0438\u0431\u0440\u0438\u0434\u043d\u0430\u044f<\/strong>. \u0413\u0434\u0435 \u042f\u043d\u0434\u0435\u043a\u0441 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0435 \u00ab\u0436\u0435\u043b\u0435\u0437\u043e\u00bb (\u0440\u043e\u0437\u0435\u0442\u043a\u0438, \u043b\u0430\u043c\u043f\u044b, \u0440\u0435\u043b\u0435), \u0430 \u0432\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u00ab\u043c\u043e\u0437\u0433\u043e\u043c\u00bb, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0438\u043c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f\u043c \u043d\u0435 \u043f\u043e\u0434 \u0441\u0438\u043b\u0443.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u043d\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c, \u0440\u0430\u0431\u043e\u0447\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u043a\u0430\u043a \u0437\u0430 20 \u043c\u0438\u043d\u0443\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 PHP \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 (Sensorbox) \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u043c\u043d\u043e\u0439 \u0440\u043e\u0437\u0435\u0442\u043a\u043e\u0439 \u042f\u043d\u0434\u0435\u043a\u0441. \u0418 \u0434\u0430, \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e.<\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%A1%D1%86%D0%B5%D0%BD%D0%B0%D1%80%D0%B8%D0%B9_%C2%AB%D0%A3%D0%BC%D0%BD%D1%8B%D0%B9_%D0%BF%D0%BE%D0%BB%D0%B8%D0%B2%C2%BB_%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B9_%D0%BD%D0%B5_%D0%BE%D1%81%D0%B8%D0%BB%D0%B8%D1%82_%D0%BE%D0%B1%D0%BB%D0%B0%D0%BA%D0%BE\" >\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439: \u00ab\u0423\u043c\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u0432\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043e\u0441\u0438\u043b\u0438\u0442 \u043e\u0431\u043b\u0430\u043a\u043e<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%A8%D0%B0%D0%B3_1_%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B0%D0%B5%D0%BC_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_API_%D0%AF%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0\" >\u0428\u0430\u0433 1. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a API \u042f\u043d\u0434\u0435\u043a\u0441\u0430<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%A8%D0%B0%D0%B3_2_Hello_Yandex_%D0%98%D0%BB%D0%B8_%D0%BF%D0%B5%D1%80%D0%B5%D1%87%D0%B5%D0%BD%D1%8C_%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D1%81_%D0%B8%D1%85_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%BF%D1%80%D1%8F%D0%BC%D0%BE_%D0%BD%D0%B0_%D0%92%D0%B0%D1%88%D0%B5%D0%BC_%D1%81%D0%B0%D0%B9%D1%82%D0%B5\" >\u0428\u0430\u0433 2. Hello, Yandex. \u0418\u043b\u0438 \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0441 \u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%93%D0%BE%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4_%D0%B4%D0%B0%D1%88%D0%B1%D0%BE%D1%80%D0%B4%D0%B0_yandex_smarthomephp\" >\u0413\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 (yandex_smarthome.php)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%9A%D0%B0%D0%BA_%D1%8D%D1%82%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82\" >\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%A8%D0%B0%D0%B3_3_%D0%9C%D0%B0%D0%B3%D0%B8%D1%8F_%D0%BF%D1%80%D0%BE%D1%81%D1%82%D1%8B%D1%85_HTTP-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2\" >\u0428\u0430\u0433 3. \u041c\u0430\u0433\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%A8%D0%B0%D0%B3_4_%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%BF%D0%BE%D0%BB%D0%B8%D0%B2%D0%B0_PHP\" >\u0428\u0430\u0433 4. \u041f\u0440\u0438\u043c\u0435\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0438\u0432\u0430 (PHP)<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%9A%D0%B0%D0%BA_%D1%8D%D1%82%D0%BE_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C\" >\u041a\u0430\u043a \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%90_%D1%87%D1%82%D0%BE_%D0%BD%D0%B0%D1%81%D1%87%D0%B5%D1%82_%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D0%B2%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%B0\" >\u0410 \u0447\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D1%8D%D1%82%D0%BE_%D0%BB%D1%83%D1%87%D1%88%D0%B5_%D1%87%D0%B5%D0%BC_%C2%AB%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE_%D0%BA%D1%83%D0%BF%D0%B8%D1%82%D1%8C_%D0%B2%D1%81%D1%91_%D0%B3%D0%BE%D1%82%D0%BE%D0%B2%D0%BE%D0%B5%C2%BB\" >\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0435, \u0447\u0435\u043c \u00ab\u043f\u0440\u043e\u0441\u0442\u043e \u043a\u0443\u043f\u0438\u0442\u044c \u0432\u0441\u0451 \u0433\u043e\u0442\u043e\u0432\u043e\u0435\u00bb?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/news.tfeya.ru\/?p=1099\/#%D0%97%D0%B0%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5\" >\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/li><\/ul><\/nav><\/div>\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%A1%D1%86%D0%B5%D0%BD%D0%B0%D1%80%D0%B8%D0%B9_%C2%AB%D0%A3%D0%BC%D0%BD%D1%8B%D0%B9_%D0%BF%D0%BE%D0%BB%D0%B8%D0%B2%C2%BB_%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B9_%D0%BD%D0%B5_%D0%BE%D1%81%D0%B8%D0%BB%D0%B8%D1%82_%D0%BE%D0%B1%D0%BB%D0%B0%D0%BA%D0%BE\"><\/span>\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439: \u00ab\u0423\u043c\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u0432\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043e\u0441\u0438\u043b\u0438\u0442 \u043e\u0431\u043b\u0430\u043a\u043e<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0443: \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0433\u0440\u044f\u0434\u043a\u0430 \u0441 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0434\u0430\u0442\u0447\u0438\u043a \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b&nbsp;<strong>Sensorbox<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0448\u043b\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440.<\/li>\n\n\n\n<li>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u0430\u044f&nbsp;<strong>\u0443\u043c\u043d\u0430\u044f \u0440\u043e\u0437\u0435\u0442\u043a\u0430 \u042f\u043d\u0434\u0435\u043a\u0441<\/strong>, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d \u0432\u043e\u0434\u044f\u043d\u043e\u0439 \u043d\u0430\u0441\u043e\u0441.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/17c\/a4f\/2cc\/17ca4f2cc159c38b9a4dce854f23ec57.png\" alt=\"\u0414\u0430\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b\" title=\"\u0414\u0430\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b\"\/><figcaption class=\"wp-element-caption\">\u0414\u0430\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0ef\/d7e\/939\/0efd7e9392338cadb202462eb27410b6.jpg\" alt=\"\u0412 \u0431\u0438\u0434\u043e\u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u0441\u043e\u0441, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a \u0443\u043c\u043d\u043e\u0439 \u0440\u043e\u0437\u0435\u0442\u043a\u0435\" title=\"\u0412 \u0431\u0438\u0434\u043e\u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u0441\u043e\u0441, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a \u0443\u043c\u043d\u043e\u0439 \u0440\u043e\u0437\u0435\u0442\u043a\u0435\"\/><figcaption class=\"wp-element-caption\">\u0412 \u0431\u0438\u0434\u043e\u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u0441\u043e\u0441, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a \u0443\u043c\u043d\u043e\u0439 \u0440\u043e\u0437\u0435\u0442\u043a\u0435<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0417\u0430\u0434\u0430\u0447\u0430:<\/strong>&nbsp;\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043d\u0430\u0441\u043e\u0441&nbsp;<em>\u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438<\/em>&nbsp;\u0441\u0440\u0435\u0434\u043d\u044f\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0447\u0432\u044b \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 3 \u0437\u0430\u043c\u0435\u0440\u0430 \u043d\u0438\u0436\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u043e\u0431\u043b\u0430\u043a\u0435 \u042f\u043d\u0434\u0435\u043a\u0441\u0430?<\/strong>&nbsp;\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0442\u0430\u043c \u043b\u0438\u043d\u0435\u0439\u043d\u044b: \u00ab\u0415\u0441\u043b\u0438 \u0434\u0430\u0442\u0447\u0438\u043a X \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 Y, \u0441\u0434\u0435\u043b\u0430\u0442\u044c Z\u00bb. \u041e\u043d\u0438 \u043d\u0435 \u0443\u043c\u0435\u044e\u0442:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u0417\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 API \u043f\u043e HTTP.<\/li>\n\n\n\n<li>\u0414\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0443\u0441\u0440\u0435\u0434\u043d\u044f\u0442\u044c \u043c\u0430\u0441\u0441\u0438\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439).<\/li>\n\n\n\n<li>\u0413\u0438\u0431\u043a\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0433\u0438\u0441\u0442\u0435\u0440\u0435\u0437\u0438\u0441\u043e\u043c (\u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u043e\u0441 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u043b\u0441\u044f\/\u0432\u044b\u043a\u043b\u044e\u0447\u0430\u043b\u0441\u044f \u043a\u0430\u0436\u0434\u0443\u044e \u043c\u0438\u043d\u0443\u0442\u0443 \u043d\u0430 \u0433\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u0420\u0435\u0448\u0435\u043d\u0438\u0435? \u041d\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 PHP-\u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0434\u0438\u0440\u0438\u0436\u0435\u0440\u043e\u043c \u044d\u0442\u043e\u0433\u043e \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430, \u0437\u0430 \u0441\u0447\u0435\u0442 \u0447\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%A8%D0%B0%D0%B3_1_%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B0%D0%B5%D0%BC_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_API_%D0%AF%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0\"><\/span>\u0428\u0430\u0433 1. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a API \u042f\u043d\u0434\u0435\u043a\u0441\u0430<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0433 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0440\u043e\u0437\u0435\u0442\u043a\u043e\u0439, \u0435\u043c\u0443 \u043d\u0443\u0436\u0435\u043d \u043a\u043b\u044e\u0447. \u042f\u043d\u0434\u0435\u043a\u0441 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 OAuth-\u043f\u0440\u043e\u0446\u0435\u0441\u0441.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u0418\u0434\u0435\u043c \u0432&nbsp;<a href=\"https:\/\/yandex.ru\/dev\/id\/doc\/ru\/\" target=\"_blank\" rel=\"noreferrer noopener\">\u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u042f\u043d\u0434\u0435\u043a\u0441 ID<\/a>&nbsp;\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/li>\n\n\n\n<li>\u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u00ab\u0412\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441\u044b\u00bb \u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u0447\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.<\/li>\n\n\n\n<li>\u0412 Redirect URI \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c&nbsp;<a href=\"https:\/\/oauth.yandex.ru\/verification_code\" target=\"_blank\" rel=\"noreferrer noopener\"><code>https:\/\/oauth.yandex.ru\/verification_code<\/code><\/a>&nbsp;(\u0434\u043b\u044f \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432).<\/li>\n\n\n\n<li>\u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0414\u043e\u0441\u0442\u0443\u043f\u044b\u00bb \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0432\u0438\u043c \u0433\u0430\u043b\u043e\u0447\u043a\u0438 \u043f\u043e \u043f\u043e\u0438\u0441\u043a\u0443 &#171;smart&#187; \u0438 &#171;home&#187;.<\/li>\n\n\n\n<li>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c&nbsp;<code>Client ID<\/code>&nbsp;\u0438&nbsp;<code>Client secret<\/code>.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/46e\/a59\/776\/46ea5977624f25c3547ba78cf43c7c95.png\" alt=\"\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0412\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u043b\u0443\u0436\u0431\u0435 \u042f\u043d\u0434\u0435\u043a\u0441\u0430\" title=\"\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0412\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u043b\u0443\u0436\u0431\u0435 \u042f\u043d\u0434\u0435\u043a\u0441\u0430\"\/><figcaption class=\"wp-element-caption\">\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0412\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u043b\u0443\u0436\u0431\u0435 \u042f\u043d\u0434\u0435\u043a\u0441\u0430<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u043e\u043f\u0438\u0441\u0430\u043d \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438:&nbsp;<\/em><a href=\"https:\/\/yandex.ru\/dev\/dialogs\/smart-home\/doc\/ru\/concepts\/platform-protocol\" rel=\"noreferrer noopener\" target=\"_blank\"><em>\u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u042f\u043d\u0434\u0435\u043a\u0441\u0430<\/em><\/a><em>.<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%A8%D0%B0%D0%B3_2_Hello_Yandex_%D0%98%D0%BB%D0%B8_%D0%BF%D0%B5%D1%80%D0%B5%D1%87%D0%B5%D0%BD%D1%8C_%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2_%D1%81_%D0%B8%D1%85_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D0%BF%D1%80%D1%8F%D0%BC%D0%BE_%D0%BD%D0%B0_%D0%92%D0%B0%D1%88%D0%B5%D0%BC_%D1%81%D0%B0%D0%B9%D1%82%D0%B5\"><\/span>\u0428\u0430\u0433 2. Hello, Yandex. \u0418\u043b\u0438 \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0441 \u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0441\u0430\u0439\u0442\u0435<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 cron-\u0441\u043a\u0440\u0438\u043f\u0442\u044b \u2014 \u044d\u0442\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u0444\u043e\u043d\u043e\u0432\u043e\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438. \u041d\u043e \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0437\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0432\u0441\u0435\u0445 10+ \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u043e\u0437\u0435\u0442\u043a\u0443 \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c \u043b\u0430\u043c\u043f\u044b?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0438\u0441\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u043d\u0430 React\/Vue \u0438 \u0431\u044d\u043a\u0435\u043d\u0434 \u043d\u0430 Laravel \u2014 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e. \u041c\u044b \u043f\u043e\u0439\u0434\u0435\u043c \u043f\u0443\u0442\u0435\u043c \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u043e\u0433\u043e \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0437\u043c\u0430:&nbsp;<strong>\u043e\u0434\u0438\u043d PHP-\u0444\u0430\u0439\u043b<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 SPA-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (Single Page Application).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f28\/ff7\/7bd\/f28ff77bd1bc92b8a42bbcac3241aef1.png\" alt=\"\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441\u0435, \u0447\u0435\u0440\u0435\u0437 \u0412\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435\" title=\"\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441\u0435, \u0447\u0435\u0440\u0435\u0437 \u0412\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435\"\/><figcaption class=\"wp-element-caption\">\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441\u0435, \u0447\u0435\u0440\u0435\u0437 \u0412\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u043e\u0438\u0442 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u041e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 (Optimistic UI).<\/strong>&nbsp;\u041e\u0431\u043b\u0430\u043a\u0430 \u0443\u043c\u043d\u044b\u0445 \u0434\u043e\u043c\u043e\u0432 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 1\u20133 \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u0412\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043c\u044b \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0442\u0443\u043c\u0431\u043b\u0435\u0440 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0435\u0440\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u043c\u044b \u0442\u0430\u043a \u0436\u0435 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043e\u0442\u043a\u0430\u0442\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0438\u0434\u0438\u0442 \u043e\u0442\u043a\u043b\u0438\u043a \u0437\u0430 0 \u043c\u0441.<\/li>\n\n\n\n<li><strong>\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b (<\/strong><code><strong>curl_multi<\/strong><\/code><strong>).<\/strong>&nbsp;\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u043f\u0440\u043e\u0441 10 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0447\u0435\u0440\u0435\u0437 API \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0437\u0430\u043d\u044f\u043b \u0431\u044b 15\u201320 \u0441\u0435\u043a\u0443\u043d\u0434. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c&nbsp;<code>curl_multi_init<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043d\u0435 \u043e\u0442\u0432\u0435\u0442\u0438\u0432\u0448\u0438\u0435 \u043d\u0430 \u043c\u0430\u0441\u0441\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e. \u042d\u0442\u043e \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u043e 2\u20133 \u0441\u0435\u043a\u0443\u043d\u0434.<\/li>\n\n\n\n<li><strong>\u0411\u043e\u0440\u044c\u0431\u0430 \u0441 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0439 PHP.<\/strong>&nbsp;\u041f\u0440\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 AJAX-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 PHP \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u0444\u0430\u0439\u043b \u0441\u0435\u0441\u0441\u0438\u0438. \u0415\u0441\u043b\u0438 \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 &#171;\u0437\u0430\u0432\u0438\u0441&#187;, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0441\u0442\u0430\u043d\u0443\u0442 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u0420\u0435\u0448\u0435\u043d\u0438\u0435: \u0432\u044b\u0437\u043e\u0432&nbsp;<code>session_write_close()<\/code>&nbsp;\u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0447\u0442\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 API-\u0440\u043e\u0443\u0442\u0435\u0440\u0435.<\/li>\n\n\n\n<li><strong>Null-safe \u043f\u0430\u0440\u0441\u0438\u043d\u0433.<\/strong>&nbsp;API \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0438\u043d\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442&nbsp;<code>null<\/code>&nbsp;\u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u043b\u044f \u043d\u043e\u0432\u044b\u0445 \u0438\u043b\u0438 \u043e\u0444\u0444\u043b\u0430\u0439\u043d-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u0416\u0435\u0441\u0442\u043a\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430&nbsp;<code>onCap?.state<\/code>&nbsp;\u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0430\u0434\u0435\u043d\u0438\u0435 JavaScript-\u043a\u043e\u0434\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439&nbsp;<code>Cannot read properties of null<\/code>.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%93%D0%BE%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4_%D0%B4%D0%B0%D1%88%D0%B1%D0%BE%D1%80%D0%B4%D0%B0_yandex_smarthomephp\"><\/span>\u0413\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 (yandex_smarthome.php)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b&nbsp;<code>yandex_smarthome.php<\/code>&nbsp;\u043d\u0430 \u0432\u0430\u0448\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u044d\u0442\u043e\u0442 \u043a\u043e\u0434. \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c&nbsp;<code>$CLIENT_ID<\/code>&nbsp;\u0438&nbsp;<code>$CLIENT_SECRET<\/code>&nbsp;\u043d\u0430 \u0432\u0430\u0448\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n&lt;?php\n\/**\n * Technofeya Home: Smart Dashboard (v9.6 - Production Ready)\n * \u041e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (SPA) \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u042f\u043d\u0434\u0435\u043a\u0441.\u0423\u043c\u043d\u044b\u043c \u0434\u043e\u043c\u043e\u043c.\n * \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438: Optimistic UI, curl_multi, null-safe parsing, session lock fix.\n *\/\nsession_start();\n\n\/\/ ==================== \u041d\u0410\u0421\u0422\u0420\u041e\u0419\u041a\u0418 ====================\n\/\/ \u0412\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0441\u044e\u0434\u0430 \u0432\u0430\u0448\u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u042f\u043d\u0434\u0435\u043a\u0441\n$CLIENT_ID     = &#039;\u0412\u0410\u0428_CLIENT_ID_\u0418\u0417_\u041a\u041e\u041d\u0421\u041e\u041b\u0418&#039;;\n$CLIENT_SECRET = &#039;\u0412\u0410\u0428_CLIENT_SECRET_\u0418\u0417_\u041a\u041e\u041d\u0421\u041e\u041b\u0418&#039;;\n$REDIRECT_URI  = &#039;https:\/\/oauth.yandex.ru\/verification_code&#039;;\n$API_BASE      = &#039;https:\/\/api.iot.yandex.net\/v1.0&#039;;\n\/\/ ===================================================\n\nfunction apiRequest($url, $method = &#039;GET&#039;, $data = null, $headers = &#x5B;]) {\n    $ch = curl_init($url);\n    curl_setopt_array($ch, &#x5B;\n        CURLOPT_RETURNTRANSFER =&gt; true,\n        CURLOPT_HTTPHEADER     =&gt; $headers,\n        CURLOPT_TIMEOUT        =&gt; 10,\n        CURLOPT_SSL_VERIFYPEER =&gt; true,\n        CURLOPT_FOLLOWLOCATION =&gt; true,\n    ]);\n\n    if ($method === &#039;POST&#039;) {\n        curl_setopt($ch, CURLOPT_POST, true);\n        if (!empty($data)) {\n            if (strpos($url, &#039;oauth.yandex.ru&#039;) !== false) {\n                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));\n            } else {\n                $headers = array_filter($headers, fn($h) =&gt; strpos($h, &#039;Content-Type&#039;) === false);\n                $headers&#x5B;] = &#039;Content-Type: application\/json&#039;;\n                curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? json_encode($data) : $data);\n                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n            }\n        }\n    }\n\n    $response = curl_exec($ch);\n    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n    curl_close($ch);\n\n    $decoded = json_decode($response, true);\n    return &#x5B;&#039;code&#039; =&gt; $httpCode, &#039;body&#039; =&gt; $decoded ?: &#x5B;&#039;raw_response&#039; =&gt; $response]];\n}\n\n\/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0432 \u0440\u0430\u0437\u044b)\nfunction apiRequestParallel($urls, $headers) {\n    $mh = curl_multi_init();\n    $curlArray = &#x5B;];\n    \n    foreach ($urls as $key =&gt; $url) {\n        $ch = curl_init($url);\n        curl_setopt_array($ch, &#x5B;\n            CURLOPT_RETURNTRANSFER =&gt; true,\n            CURLOPT_HTTPHEADER     =&gt; $headers,\n            CURLOPT_TIMEOUT        =&gt; 10,\n            CURLOPT_SSL_VERIFYPEER =&gt; true,\n        ]);\n        curl_multi_add_handle($mh, $ch);\n        $curlArray&#x5B;$key] = $ch;\n    }\n    \n    $running = null;\n    do { curl_multi_exec($mh, $running); } while ($running &gt; 0);\n    \n    $results = &#x5B;];\n    foreach ($curlArray as $key =&gt; $ch) {\n        $response = curl_multi_getcontent($ch);\n        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n        $decoded = json_decode($response, true);\n        $results&#x5B;$key] = &#x5B;&#039;code&#039; =&gt; $httpCode, &#039;body&#039; =&gt; $decoded ?: &#x5B;&#039;raw_response&#039; =&gt; $response]];\n        curl_multi_remove_handle($mh, $ch);\n    }\n    curl_multi_close($mh);\n    return $results;\n}\n\n\/\/ ==================== API ROUTER (\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 AJAX) ====================\nif (isset($_GET&#x5B;&#039;api&#039;]) &amp;&amp; isset($_SESSION&#x5B;&#039;yandex_token&#039;])) {\n    header(&#039;Content-Type: application\/json&#039;);\n    $token = $_SESSION&#x5B;&#039;yandex_token&#039;];\n    \n    \/\/ \u041a\u0420\u0418\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u0412\u0410\u0416\u041d\u041e: \u0441\u043d\u0438\u043c\u0430\u0435\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u0441\u0435\u0441\u0441\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0435 AJAX-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0435 \u0432\u0438\u0441\u0435\u043b\u0438\n    session_write_close();\n    $iotHeaders = &#x5B;&quot;Authorization: Bearer {$token}&quot;];\n\n    if ($_GET&#x5B;&#039;api&#039;] === &#039;devices&#039;) {\n        \/\/ 1. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\n        $infoRes = apiRequest(&quot;{$API_BASE}\/user\/info&quot;, &#039;GET&#039;, null, $iotHeaders);\n        if ($infoRes&#x5B;&#039;code&#039;] !== 200 || !isset($infoRes&#x5B;&#039;body&#039;]&#x5B;&#039;devices&#039;])) {\n            echo json_encode(&#x5B;&#039;error&#039; =&gt; &#039;\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432&#039;, &#039;details&#039; =&gt; $infoRes&#x5B;&#039;body&#039;]]);\n            exit;\n        }\n        \n        $devices = $infoRes&#x5B;&#039;body&#039;]&#x5B;&#039;devices&#039;];\n        $deviceIds = array_map(fn($d) =&gt; &#x5B;&#039;id&#039; =&gt; $d&#x5B;&#039;id&#039;]], $devices);\n        \n        \/\/ 2. \u041f\u0440\u043e\u0431\u0443\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u043c\u0430\u0441\u0441\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439\n        $queryRes = apiRequest(&quot;{$API_BASE}\/user\/devices\/query&quot;, &#039;POST&#039;, &#x5B;&#039;devices&#039; =&gt; $deviceIds], $iotHeaders);\n        $states = &#x5B;];\n        \n        if ($queryRes&#x5B;&#039;code&#039;] === 200 &amp;&amp; isset($queryRes&#x5B;&#039;body&#039;]&#x5B;&#039;devices&#039;])) {\n            foreach ($queryRes&#x5B;&#039;body&#039;]&#x5B;&#039;devices&#039;] as $devState) {\n                $states&#x5B;$devState&#x5B;&#039;id&#039;]] = $devState&#x5B;&#039;capabilities&#039;] ?? &#x5B;];\n            }\n        }\n        \n        \/\/ 3. Fallback: \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0433\u0434\u0435 \u043d\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\n        $missing = array_filter($devices, fn($d) =&gt; !isset($states&#x5B;$d&#x5B;&#039;id&#039;]]));\n        if (count($missing) &gt; 0) {\n            $urls = array_map(fn($d) =&gt; &quot;{$API_BASE}\/devices\/{$d&#x5B;&#039;id&#039;]}&quot;, $missing);\n            $parallelRes = apiRequestParallel($urls, $iotHeaders);\n            \n            foreach ($parallelRes as $key =&gt; $res) {\n                if ($res&#x5B;&#039;code&#039;] === 200 &amp;&amp; isset($res&#x5B;&#039;body&#039;]&#x5B;&#039;capabilities&#039;])) {\n                    $devId = $missing&#x5B;$key]&#x5B;&#039;id&#039;];\n                    $states&#x5B;$devId] = $res&#x5B;&#039;body&#039;]&#x5B;&#039;capabilities&#039;];\n                    $devices&#x5B;array_search($devId, array_column($devices, &#039;id&#039;))]&#x5B;&#039;device_state&#039;] = $res&#x5B;&#039;body&#039;]&#x5B;&#039;state&#039;] ?? &#039;unknown&#039;;\n                }\n            }\n        }\n        \n        \/\/ 4. \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430\n        foreach ($devices as &amp;$dev) {\n            $dev&#x5B;&#039;current_state&#039;] = $states&#x5B;$dev&#x5B;&#039;id&#039;]] ?? &#x5B;];\n            if (!isset($dev&#x5B;&#039;device_state&#039;])) {\n                $dev&#x5B;&#039;device_state&#039;] = &#039;unknown&#039;;\n            }\n        }\n        \n        echo json_encode(&#x5B;&#039;success&#039; =&gt; true, &#039;devices&#039; =&gt; $devices]);\n        exit;\n    }\n\n    if ($_GET&#x5B;&#039;api&#039;] === &#039;action&#039;) {\n        $rawInput = file_get_contents(&#039;php:\/\/input&#039;);\n        $input = json_decode($rawInput, true) ?: $_POST;\n\n        if (empty($input) || !isset($input&#x5B;&#039;devices&#039;])) {\n            echo json_encode(&#x5B;&#039;success&#039; =&gt; false, &#039;error&#039; =&gt; &#039;\u041f\u0443\u0441\u0442\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435&#039;]);\n            exit;\n        }\n\n        $res = apiRequest(&quot;{$API_BASE}\/devices\/actions&quot;, &#039;POST&#039;, $input, $iotHeaders);\n        if ($res&#x5B;&#039;code&#039;] === 200 || $res&#x5B;&#039;code&#039;] === 202) {\n            echo json_encode(&#x5B;&#039;success&#039; =&gt; true]);\n        } else {\n            echo json_encode(&#x5B;&#039;success&#039; =&gt; false, &#039;error&#039; =&gt; &quot;HTTP {$res&#x5B;&#039;code&#039;]}&quot;, &#039;details&#039; =&gt; $res&#x5B;&#039;body&#039;]]);\n        }\n        exit;\n    }\n}\n\n\/\/ ==================== \u041b\u041e\u0413\u0418\u041a\u0410 \u0410\u0412\u0422\u041e\u0420\u0418\u0417\u0410\u0426\u0418\u0418 ====================\nif (isset($_POST&#x5B;&#039;manual_code&#039;]) &amp;&amp; !isset($_SESSION&#x5B;&#039;yandex_token&#039;])) {\n    $res = apiRequest(&#039;https:\/\/oauth.yandex.ru\/token&#039;, &#039;POST&#039;, &#x5B;\n        &#039;grant_type&#039; =&gt; &#039;authorization_code&#039;, &#039;code&#039; =&gt; trim($_POST&#x5B;&#039;manual_code&#039;]),\n        &#039;client_id&#039; =&gt; $CLIENT_ID, &#039;client_secret&#039; =&gt; $CLIENT_SECRET, &#039;redirect_uri&#039; =&gt; $REDIRECT_URI\n    ]);\n\n    if ($res&#x5B;&#039;code&#039;] == 200 &amp;&amp; isset($res&#x5B;&#039;body&#039;]&#x5B;&#039;access_token&#039;])) {\n        $_SESSION&#x5B;&#039;yandex_token&#039;] = $res&#x5B;&#039;body&#039;]&#x5B;&#039;access_token&#039;];\n        $userInfo = apiRequest(&#039;https:\/\/login.yandex.ru\/info?format=json&#039;, &#039;GET&#039;, null, &#x5B;&#039;Authorization: OAuth &#039; . $_SESSION&#x5B;&#039;yandex_token&#039;]]);\n        $_SESSION&#x5B;&#039;yandex_user&#039;] = $userInfo&#x5B;&#039;body&#039;]&#x5B;&#039;login&#039;] ?? &#039;User&#039;;\n        header(&#039;Location: &#039; . strtok($_SERVER&#x5B;&quot;REQUEST_URI&quot;], &#039;?&#039;));\n        exit;\n    }\n    $authError = &quot;\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438: &quot; . json_encode($res&#x5B;&#039;body&#039;]);\n}\n\nif (!isset($_SESSION&#x5B;&#039;yandex_token&#039;])) {\n    $authUrl = &quot;https:\/\/oauth.yandex.ru\/authorize?response_type=code&amp;client_id={$CLIENT_ID}&amp;redirect_uri=&quot; . urlencode($REDIRECT_URI);\n    die(&quot;&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=&#039;utf-8&#039;&gt;&lt;title&gt;\u0412\u0445\u043e\u0434 \u0432 \u0423\u043c\u043d\u044b\u0439 \u0434\u043e\u043c&lt;\/title&gt;\n    &lt;style&gt;body{font-family:system-ui;max-width:400px;margin:100px auto;padding:20px;text-align:center;background:#f5f5f7}\n    .card{background:#fff;padding:30px;border-radius:16px;box-shadow:0 4px 20px rgba(0,0,0,0.08)}\n    .btn{display:block;width:100%;padding:14px;background:#fc0;color:#000;border:none;border-radius:10px;font-weight:bold;font-size:16px;cursor:pointer;margin:15px 0;text-decoration:none}\n    input{width:100%;padding:12px;border:1px solid #ddd;border-radius:10px;margin:10px 0;box-sizing:border-box;text-align:center}&lt;\/style&gt;&lt;\/head&gt;\n    &lt;body&gt;&lt;div class=&#039;card&#039;&gt;&lt;h2&gt;\ud83d\udd0c Technofeya Home&lt;\/h2&gt;\n    &quot; . (isset($authError) ? &quot;&lt;p style=&#039;color:red;font-size:14px&#039;&gt;$authError&lt;\/p&gt;&quot; : &quot;&quot;) . &quot;\n    &lt;p style=&#039;font-size:14px;color:#666&#039;&gt;1. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u043d\u0438\u0436\u0435.&lt;br&gt;2. \u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435 \u0434\u043e\u0441\u0442\u0443\u043f \u0432 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0435 \u042f\u043d\u0434\u0435\u043a\u0441\u0430.&lt;br&gt;3. \u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u043a\u043e\u0434 \u0438 \u0432\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0435\u0433\u043e \u0441\u044e\u0434\u0430.&lt;\/p&gt;\n    &lt;a href=&#039;$authUrl&#039; target=&#039;_blank&#039; class=&#039;btn&#039;&gt;\ud83d\udd11 \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u0434 \u043e\u0442 \u042f\u043d\u0434\u0435\u043a\u0441\u0430&lt;\/a&gt;\n    &lt;form method=&#039;POST&#039;&gt;&lt;input type=&#039;text&#039; name=&#039;manual_code&#039; placeholder=&#039;\u0412\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043a\u043e\u0434&#039; required&gt;&lt;button class=&#039;btn&#039; style=&#039;background:#007aff;color:#fff&#039;&gt;\u0412\u043e\u0439\u0442\u0438&lt;\/button&gt;&lt;\/form&gt;&lt;\/div&gt;&lt;\/body&gt;&lt;\/html&gt;&quot;);\n}\n?&gt;\n&lt;!DOCTYPE html&gt;\n&lt;html lang=&quot;ru&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\n    &lt;title&gt;Technofeya Home Dashboard&lt;\/title&gt;\n    &lt;!-- \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c Tailwind CSS \u0434\u043b\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 --&gt;\n    &lt;script src=&quot;https:\/\/cdn.tailwindcss.com&quot;&gt;&lt;\/script&gt;\n    &lt;style&gt;\n        .toggle-checkbox:checked { right: 0; border-color: #34c759; }\n        .toggle-checkbox:checked + .toggle-label { background-color: #34c759; }\n        .glass-panel { background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }\n        .loader { border: 3px solid #f3f3f3; border-top: 3px solid #007aff; border-radius: 50%; width: 24px; height: 24px; animation: spin 1s linear infinite; }\n        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body class=&quot;bg-gray-100 text-gray-800 font-sans min-h-screen&quot;&gt;\n\n    &lt;header class=&quot;glass-panel sticky top-0 z-50 border-b border-gray-200 shadow-sm&quot;&gt;\n        &lt;div class=&quot;max-w-4xl mx-auto px-4 py-4 flex justify-between items-center&quot;&gt;\n            &lt;h1 class=&quot;text-xl font-bold flex items-center gap-2&quot;&gt;\ud83d\udd0c Technofeya Home &lt;span class=&quot;text-xs font-normal text-gray-500 bg-gray-200 px-2 py-1 rounded-full&quot;&gt;v9.6&lt;\/span&gt;&lt;\/h1&gt;\n            &lt;div class=&quot;flex items-center gap-3&quot;&gt;\n                &lt;span class=&quot;text-sm text-gray-600 hidden sm:inline&quot;&gt;\ud83d\udc64 &lt;?= htmlspecialchars($_SESSION&#x5B;&#039;yandex_user&#039;]) ?&gt;&lt;\/span&gt;\n                &lt;button onclick=&quot;window.location.href=&#039;?action=logout&#039;&quot; class=&quot;text-sm text-red-500 hover:text-red-700 font-medium border border-red-200 px-3 py-1 rounded-lg hover:bg-red-50 transition&quot;&gt;\u0412\u044b\u0439\u0442\u0438&lt;\/button&gt;\n            &lt;\/div&gt;\n        &lt;\/div&gt;\n    &lt;\/header&gt;\n\n    &lt;main class=&quot;max-w-4xl mx-auto px-4 py-8&quot;&gt;\n        &lt;div class=&quot;flex justify-between items-center mb-6&quot;&gt;\n            &lt;h2 class=&quot;text-2xl font-semibold&quot;&gt;\u041c\u043e\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430&lt;\/h2&gt;\n            &lt;button onclick=&quot;loadDevices()&quot; class=&quot;bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition shadow-sm&quot;&gt;\n                &lt;span id=&quot;refresh-icon&quot;&gt;\ud83d\udd04&lt;\/span&gt; \u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\n            &lt;\/button&gt;\n        &lt;\/div&gt;\n        &lt;div id=&quot;devices-grid&quot; class=&quot;grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5&quot;&gt;\n            &lt;div class=&quot;col-span-full text-center py-20 text-gray-500&quot;&gt;\n                &lt;div class=&quot;loader mx-auto mb-4&quot;&gt;&lt;\/div&gt;\n                \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432...\n            &lt;\/div&gt;\n        &lt;\/div&gt;\n    &lt;\/main&gt;\n\n    &lt;div id=&quot;toast&quot; class=&quot;fixed bottom-5 right-5 bg-gray-800 text-white px-6 py-3 rounded-lg shadow-xl transform translate-y-20 opacity-0 transition-all duration-300 z-50 max-w-sm break-words&quot;&gt;&lt;\/div&gt;\n\n    &lt;script&gt;\n        async function loadDevices() {\n            const grid = document.getElementById(&#039;devices-grid&#039;);\n            const btn = document.getElementById(&#039;refresh-icon&#039;);\n            btn.classList.add(&#039;animate-spin&#039;);\n            \n            try {\n                const res = await fetch(&#039;?api=devices&#039;);\n                const data = await res.json();\n                \n                if (data.error) {\n                    grid.innerHTML = `&lt;div class=&quot;col-span-full bg-red-100 text-red-700 p-4 rounded-lg border border-red-200&quot;&gt;${data.error}&lt;\/div&gt;`;\n                    return;\n                }\n\n                grid.innerHTML = &#039;&#039;;\n                if (!data.devices || data.devices.length === 0) {\n                    grid.innerHTML = `&lt;div class=&quot;col-span-full text-center text-gray-500 py-10&quot;&gt;\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.&lt;\/div&gt;`;\n                    return;\n                }\n\n                data.devices.forEach(dev =&gt; grid.appendChild(createDeviceCard(dev)));\n                showToast(&#039;\u2705 \u0421\u043f\u0438\u0441\u043e\u043a \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d&#039;);\n            } catch (e) {\n                grid.innerHTML = `&lt;div class=&quot;col-span-full bg-red-100 text-red-700 p-4 rounded-lg&quot;&gt;\u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0442\u0438: ${e.message}&lt;\/div&gt;`;\n            } finally {\n                btn.classList.remove(&#039;animate-spin&#039;);\n            }\n        }\n\n        function createDeviceCard(dev) {\n            const state = dev.current_state || &#x5B;];\n            const onCap = state.find(c =&gt; c.type === &#039;devices.capabilities.on_off&#039;);\n            \n            \/\/ NULL-SAFE: \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u042f\u043d\u0434\u0435\u043a\u0441 \u0432\u0435\u0440\u043d\u0443\u043b null\n            const capState = onCap?.state || {}; \n            const isRetrievable = onCap ? onCap.retrievable : false;\n            const isOn = isRetrievable ? !!capState.value : false;\n            const lastUpdated = isRetrievable &amp;&amp; capState.last_updated ? capState.last_updated : 0;\n            const isStale = lastUpdated &gt; 0 &amp;&amp; (Date.now() \/ 1000 - lastUpdated) &gt; 3600; \/\/ \u0421\u0442\u0430\u0440\u0448\u0435 1 \u0447\u0430\u0441\u0430\n            \n            const deviceState = dev.device_state || &#039;unknown&#039;;\n            const isOffline = deviceState === &#039;offline&#039;;\n\n            let statusBadge = &#039;&#039;;\n            if (isOffline) {\n                statusBadge = `&lt;span class=&quot;text-&#x5B;10px] bg-gray-200 text-gray-600 px-2 py-0.5 rounded-full&quot;&gt;\ud83d\udce1 \u041d\u0435 \u0432 \u0441\u0435\u0442\u0438&lt;\/span&gt;`;\n            } else if (isStale) {\n                statusBadge = `&lt;span class=&quot;text-&#x5B;10px] bg-yellow-100 text-yellow-700 px-2 py-0.5 rounded-full&quot; title=&quot;\u0421\u0442\u0430\u0442\u0443\u0441 \u043d\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u043b\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0430&quot;&gt;\u26a0\ufe0f \u0423\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435&lt;\/span&gt;`;\n            } else if (!isRetrievable) {\n                statusBadge = `&lt;span class=&quot;text-&#x5B;10px] bg-blue-100 text-blue-700 px-2 py-0.5 rounded-full&quot; title=&quot;\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043d\u0435 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0441\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u0443\u0441&quot;&gt;\u2753 \u0421\u0442\u0430\u0442\u0443\u0441 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d&lt;\/span&gt;`;\n            }\n\n            let extraControls = &#039;&#039;;\n            const rangeCap = state.find(c =&gt; c.type === &#039;devices.capabilities.range&#039;);\n            if (rangeCap &amp;&amp; rangeCap.retrievable &amp;&amp; rangeCap?.state) {\n                const val = rangeCap.state.value;\n                const min = rangeCap.parameters?.range?.min || 1;\n                const max = rangeCap.parameters?.range?.max || 100;\n                const instance = rangeCap.state.instance;\n                const label = instance === &#039;brightness&#039; ? &#039;\u042f\u0440\u043a\u043e\u0441\u0442\u044c&#039; : (instance === &#039;temperature&#039; ? &#039;\u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430&#039; : &#039;\u0423\u0440\u043e\u0432\u0435\u043d\u044c&#039;);\n                \n                extraControls += `\n                    &lt;div class=&quot;mt-4 pt-4 border-t border-gray-100&quot;&gt;\n                        &lt;div class=&quot;flex justify-between text-xs text-gray-500 mb-1&quot;&gt;\n                            &lt;span&gt;${label}&lt;\/span&gt;\n                            &lt;span id=&quot;val-${dev.id}-${instance}&quot; class=&quot;font-bold text-blue-600&quot;&gt;${val}&lt;\/span&gt;\n                        &lt;\/div&gt;\n                        &lt;input type=&quot;range&quot; min=&quot;${min}&quot; max=&quot;${max}&quot; value=&quot;${val}&quot; \n                            class=&quot;w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-500&quot;\n                            onchange=&quot;sendRangeAction(&#039;${dev.id}&#039;, &#039;${instance}&#039;, this.value)&quot; ${isOffline ? &#039;disabled&#039; : &#039;&#039;}&gt;\n                    &lt;\/div&gt;\n                `;\n            }\n\n            const card = document.createElement(&#039;div&#039;);\n            card.id = `card-${dev.id}`;\n            card.className = `glass-panel rounded-2xl p-5 shadow-sm border border-white\/60 hover:shadow-md transition relative overflow-hidden ${isOffline ? &#039;opacity-75&#039; : &#039;&#039;}`;\n            card.innerHTML = `\n                &lt;div class=&quot;absolute top-0 right-0 w-24 h-24 bg-gradient-to-br from-blue-50 to-transparent rounded-bl-full -mr-4 -mt-4&quot;&gt;&lt;\/div&gt;\n                &lt;div class=&quot;relative z-10&quot;&gt;\n                    &lt;div class=&quot;flex justify-between items-start mb-2&quot;&gt;\n                        &lt;div&gt;\n                            &lt;h3 class=&quot;font-bold text-lg text-gray-800 leading-tight flex items-center gap-2&quot;&gt;\n                                ${dev.name}\n                                ${statusBadge}\n                            &lt;\/h3&gt;\n                            &lt;p class=&quot;text-&#x5B;10px] text-gray-400 mt-1 font-mono truncate w-40&quot; title=&quot;${dev.id}&quot;&gt;${dev.id}&lt;\/p&gt;\n                        &lt;\/div&gt;\n                        &lt;div id=&quot;status-${dev.id}&quot; class=&quot;status-indicator w-3 h-3 rounded-full mt-1.5 ${isOn ? &#039;bg-green-500 shadow-&#x5B;0_0_8px_rgba(34,197,94,0.6)]&#039; : &#039;bg-gray-300&#039;}&quot;&gt;&lt;\/div&gt;\n                    &lt;\/div&gt;\n                    \n                    &lt;div class=&quot;flex items-center justify-between mt-4&quot;&gt;\n                        &lt;span id=&quot;text-${dev.id}&quot; class=&quot;text-sm font-medium ${isOn ? &#039;text-green-600&#039; : &#039;text-gray-400&#039;}&quot;&gt;\n                            ${isOn ? &#039;\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u043e&#039; : (isRetrievable ? &#039;\u0412\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043e&#039; : &#039;\u0421\u0442\u0430\u0442\u0443\u0441 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d&#039;)}\n                        &lt;\/span&gt;\n                        \n                        &lt;label class=&quot;relative inline-flex items-center cursor-pointer ${isOffline ? &#039;opacity-50 cursor-not-allowed&#039; : &#039;&#039;}&quot;&gt;\n                            &lt;input type=&quot;checkbox&quot; id=&quot;toggle-${dev.id}&quot; class=&quot;sr-only toggle-checkbox&quot; ${isOn ? &#039;checked&#039; : &#039;&#039;} \n                                onchange=&quot;sendOnOffAction(&#039;${dev.id}&#039;, this.checked)&quot; ${isOffline ? &#039;disabled&#039; : &#039;&#039;}&gt;\n                            &lt;div class=&quot;w-11 h-6 bg-gray-200 rounded-full toggle-label transition-colors duration-300&quot;&gt;&lt;\/div&gt;\n                            &lt;div id=&quot;knob-${dev.id}&quot; class=&quot;absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300 transform ${isOn ? &#039;translate-x-5&#039; : &#039;translate-x-0&#039;} shadow-sm&quot;&gt;&lt;\/div&gt;\n                        &lt;\/label&gt;\n                    &lt;\/div&gt;\n                    ${extraControls}\n                &lt;\/div&gt;\n            `;\n            return card;\n        }\n\n        \/\/ \u041c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (Optimistic UI)\n        function updateDeviceUI(deviceId, isOn) {\n            const status = document.getElementById(`status-${deviceId}`);\n            const text = document.getElementById(`text-${deviceId}`);\n            const toggle = document.getElementById(`toggle-${deviceId}`);\n            const knob = document.getElementById(`knob-${deviceId}`);\n            \n            if (status) status.className = `status-indicator w-3 h-3 rounded-full mt-1.5 ${isOn ? &#039;bg-green-500 shadow-&#x5B;0_0_8px_rgba(34,197,94,0.6)]&#039; : &#039;bg-gray-300&#039;}`;\n            if (text) {\n                text.className = `text-sm font-medium ${isOn ? &#039;text-green-600&#039; : &#039;text-gray-400&#039;}`;\n                text.textContent = isOn ? &#039;\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u043e&#039; : &#039;\u0412\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043e&#039;;\n            }\n            if (toggle) toggle.checked = isOn;\n            if (knob) knob.className = `absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform duration-300 transform ${isOn ? &#039;translate-x-5&#039; : &#039;translate-x-0&#039;} shadow-sm`;\n        }\n\n        async function sendAction(deviceId, payload, optimisticUpdate = null) {\n            showToast(&#039;\u23f3 \u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b...&#039;, &#039;info&#039;);\n            if (optimisticUpdate !== null) updateDeviceUI(deviceId, optimisticUpdate);\n            \n            try {\n                const res = await fetch(&#039;?api=action&#039;, {\n                    method: &#039;POST&#039;,\n                    headers: {&#039;Content-Type&#039;: &#039;application\/json&#039;},\n                    body: JSON.stringify({devices: &#x5B;{id: deviceId, actions: &#x5B;payload]}]})\n                });\n                const data = await res.json();\n                \n                if (data.success) {\n                    showToast(&#039;\u2705 \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430&#039;);\n                    \/\/ \u0424\u043e\u043d\u043e\u0432\u0430\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 5 \u0441\u0435\u043a\u0443\u043d\u0434, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u043b\u0430\u043a\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\n                    setTimeout(loadDevices, 5000);\n                } else {\n                    showToast(&#039;\u274c &#039; + (data.error || &#039;\u041e\u0448\u0438\u0431\u043a\u0430&#039;) + (data.details ? &#039;: &#039; + JSON.stringify(data.details) : &#039;&#039;), &#039;error&#039;);\n                    \/\/ \u041e\u0442\u043a\u0430\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435\n                    if (optimisticUpdate !== null) updateDeviceUI(deviceId, !optimisticUpdate);\n                }\n            } catch (e) {\n                showToast(&#039;\u274c \u041e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0442\u0438: &#039; + e.message, &#039;error&#039;);\n                if (optimisticUpdate !== null) updateDeviceUI(deviceId, !optimisticUpdate);\n            }\n        }\n\n        function sendOnOffAction(deviceId, isOn) {\n            sendAction(deviceId, {type: &#039;devices.capabilities.on_off&#039;, state: {instance: &#039;on&#039;, value: isOn}}, isOn);\n        }\n\n        function sendRangeAction(deviceId, instance, value) {\n            const el = document.getElementById(`val-${deviceId}-${instance}`);\n            if (el) el.innerText = value;\n            sendAction(deviceId, {type: &#039;devices.capabilities.range&#039;, state: {instance: instance, value: parseInt(value)}});\n        }\n\n        function showToast(msg, type = &#039;success&#039;) {\n            const toast = document.getElementById(&#039;toast&#039;);\n            toast.innerText = msg;\n            toast.className = `fixed bottom-5 right-5 px-6 py-3 rounded-lg shadow-xl transform transition-all duration-300 z-50 text-white text-sm ${type === &#039;error&#039; ? &#039;bg-red-500&#039; : (type === &#039;info&#039; ? &#039;bg-gray-600&#039; : &#039;bg-green-600&#039;)}`;\n            toast.style.transform = &#039;translateY(0)&#039;;\n            toast.style.opacity = &#039;1&#039;;\n            setTimeout(() =&gt; {\n                toast.style.transform = &#039;translateY(20px)&#039;;\n                toast.style.opacity = &#039;0&#039;;\n            }, 4000);\n        }\n\n        document.addEventListener(&#039;DOMContentLoaded&#039;, loadDevices);\n    &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%9A%D0%B0%D0%BA_%D1%8D%D1%82%D0%BE_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82\"><\/span>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u043e\u043a\u0430\u0436\u0435\u0442 \u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u043a\u043e\u0434\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u042f\u043d\u0434\u0435\u043a\u0441\u0430.<\/li>\n\n\n\n<li>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0432\u0445\u043e\u0434\u0430 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0441\u0435\u0442\u043a\u0443 \u043a\u0430\u0440\u0442\u043e\u0447\u0435\u043a \u0432\u0441\u0435\u0445 \u0432\u0430\u0448\u0438\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432.<\/li>\n\n\n\n<li>\u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u043b\u044e\u0431\u043e\u0439 \u0440\u043e\u0437\u0435\u0442\u043a\u0438. \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f&nbsp;<strong>\u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e<\/strong>&nbsp;(\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f Optimistic UI), \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0443\u0439\u0434\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0447\u0435\u0440\u0435\u0437 5 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0442\u0438\u0445\u0430\u044f \u0444\u043e\u043d\u043e\u0432\u0430\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430.<\/li>\n\n\n\n<li>\u0415\u0441\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043e\u0444\u0444\u043b\u0430\u0439\u043d, \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u043e\u043b\u0443\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0439, \u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u0432\u0430\u0441 \u0432 \u0437\u0430\u0431\u043b\u0443\u0436\u0434\u0435\u043d\u0438\u0435.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u0435\u043d, \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u043e\u0432 (Webpack\/Vite) \u0438\u043b\u0438 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u0433\u043e\u0442\u043e\u0432 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0445\u043e\u0441\u0442\u0438\u043d\u0433.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%A8%D0%B0%D0%B3_3_%D0%9C%D0%B0%D0%B3%D0%B8%D1%8F_%D0%BF%D1%80%D0%BE%D1%81%D1%82%D1%8B%D1%85_HTTP-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2\"><\/span>\u0428\u0430\u0433 3. \u041c\u0430\u0433\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u0445 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412\u0441\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0432\u0443\u0445 \u0432\u0435\u0449\u0430\u0445:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u041c\u044b \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 GET-\u0437\u0430\u043f\u0440\u043e\u0441.<\/li>\n\n\n\n<li>\u041c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441 \u0447\u0435\u0440\u0435\u0437 POST-\u0437\u0430\u043f\u0440\u043e\u0441 \u0441 JSON-\u0442\u0435\u043b\u043e\u043c.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430\u0448 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 Sensorbox. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043e\u043d \u043e\u0442\u0434\u0430\u0435\u0442 \u0447\u0438\u0441\u0442\u044b\u0439 JSON:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nhttps:\/\/iot.tfeya.ru\/sensorData.php?login=eugene&amp;amp;sensor_id=1&amp;amp;secret=001c0ee0805bd121xxxxxxxxxxxxxeb9ad576&amp;amp;json=1\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041e\u0442\u0432\u0435\u0442:<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n{&quot;val&quot;:&quot;50&quot;,&quot;datetime&quot;:&quot;2026-05-30 23:06:01&quot;}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><em>(\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435&nbsp;<\/em><code><em>50<\/em><\/code><em>&nbsp;\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0443\u0445\u043e\u0441\u0442\u044c).<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%A8%D0%B0%D0%B3_4_%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%BF%D0%BE%D0%BB%D0%B8%D0%B2%D0%B0_PHP\"><\/span>\u0428\u0430\u0433 4. \u041f\u0440\u0438\u043c\u0435\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0438\u0432\u0430 (PHP)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439, \u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442&nbsp;<code>auto_watering.php<\/code>. \u041e\u043d \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u043e\u0432\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0438: \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0434\u0430\u0442\u0447\u0438\u043a (\u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043d\u0435 \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u043c, \u043d\u043e \u0441\u0443\u0442\u044c \u0412\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0435), \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0438 \u0434\u0435\u0440\u0433\u0430\u0435\u0442 \u0440\u043e\u0437\u0435\u0442\u043a\u0443 \u042f\u043d\u0434\u0435\u043a\u0441\u0430.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n&lt;?php\n\/**\n * auto_watering.php - \u0413\u0438\u0431\u0440\u0438\u0434\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430\n *\/\n\n\/\/ === \u041d\u0410\u0421\u0422\u0420\u041e\u0419\u041a\u0418 ===\n$YANDEX_TOKEN  = &#039;\u0412\u0410\u0428_OAUTH_TOKEN_\u0417\u0414\u0415\u0421\u042c&#039;; \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 OAuth\n$DEVICE_ID     = &#039;19aae231-xxxxx-xxxx-.....&#039;; \/\/ ID \u0440\u043e\u0437\u0435\u0442\u043a\u0438 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u042f\u043d\u0434\u0435\u043a\u0441\n$SENSOR_URL    = &#039;https:\/\/iot.tfeya.ru\/sensorData.php?login=eugene&amp;sensor_id=1&amp;secret=00xxxxxxxx121cba99c83eec54f0f43a0eeeb9ad576&amp;json=1&#039;;\n$DRY_THRESHOLD = 15; \/\/ \u041f\u043e\u0440\u043e\u0433 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438, \u043d\u0438\u0436\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u043b\u0438\u0432 (%)\n\n\/\/ 1. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430\n$sensorDataJson = file_get_contents($SENSOR_URL);\n$sensorData = json_decode($sensorDataJson, true);\n\nif (!$sensorData || !isset($sensorData&#x5B;&#039;val&#039;])) {\n    die(&quot;\u041e\u0448\u0438\u0431\u043a\u0430: \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 Sensorbox&quot;);\n}\n\n$currentMoisture = (int)$sensorData&#x5B;&#039;val&#039;];\necho &quot;\u0422\u0435\u043a\u0443\u0449\u0430\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u044c: {$currentMoisture}%\\n&quot;;\n\n\/\/ 2. \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f (\u0437\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0443\u0441\u0440\u0435\u0434\u043d\u0435\u043d\u0438\u0435, \u0433\u0438\u0441\u0442\u0435\u0440\u0435\u0437\u0438\u0441 \u0438 \u0442.\u0434.)\n$shouldWater = ($currentMoisture &lt; $DRY_THRESHOLD);\n\n\/\/ 3. \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u042f\u043d\u0434\u0435\u043a\u0441.\u0423\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430\n\/\/ \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f: https:\/\/yandex.ru\/dev\/dialogs\/smart-home\/doc\/ru\/concepts\/control-api\n$payload = &#x5B;\n    &quot;devices&quot; =&gt; &#x5B;&#x5B;\n        &quot;id&quot; =&gt; $DEVICE_ID,\n        &quot;actions&quot; =&gt; &#x5B;&#x5B;\n            &quot;type&quot; =&gt; &quot;devices.capabilities.on_off&quot;,\n            &quot;state&quot; =&gt; &#x5B;\n                &quot;instance&quot; =&gt; &quot;on&quot;,\n                &quot;value&quot; =&gt; $shouldWater \/\/ true \u0438\u043b\u0438 false\n            ]\n        ]]\n    ]]\n];\n\n\/\/ 4. \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u042f\u043d\u0434\u0435\u043a\u0441\n$ch = curl_init(&#039;https:\/\/api.iot.yandex.net\/v1.0\/devices\/actions&#039;);\ncurl_setopt_array($ch, &#x5B;\n    CURLOPT_RETURNTRANSFER =&gt; true,\n    CURLOPT_POST =&gt; true,\n    CURLOPT_POSTFIELDS =&gt; json_encode($payload),\n    CURLOPT_HTTPHEADER =&gt; &#x5B;\n        &#039;Authorization: Bearer &#039; . $YANDEX_TOKEN,\n        &#039;Content-Type: application\/json&#039;\n    ],\n    CURLOPT_TIMEOUT =&gt; 10\n]);\n\n$response = curl_exec($ch);\n$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\ncurl_close($ch);\n\n\/\/ 5. \u0412\u044b\u0432\u043e\u0434 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\nif ($httpCode === 200 || $httpCode === 202) {\n    $actionText = $shouldWater ? &quot;\u0412\u041a\u041b\u042e\u0427\u0415\u041d (\u043f\u043e\u043b\u0438\u0432)&quot; : &quot;\u0412\u042b\u041a\u041b\u042e\u0427\u0415\u041d (\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u043b\u0430\u0433\u0438)&quot;;\n    echo &quot;\u2705 \u0423\u0441\u043f\u0435\u0445! \u0420\u043e\u0437\u0435\u0442\u043a\u0430 \u042f\u043d\u0434\u0435\u043a\u0441 {$actionText}.\\n&quot;;\n} else {\n    echo &quot;\u274c \u041e\u0448\u0438\u0431\u043a\u0430 API \u042f\u043d\u0434\u0435\u043a\u0441\u0430 (HTTP {$httpCode}): {$response}\\n&quot;;\n}\n?&gt;\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%9A%D0%B0%D0%BA_%D1%8D%D1%82%D0%BE_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C\"><\/span>\u041a\u0430\u043a \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c?<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0435 \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043d\u0430 \u0441\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,&nbsp;<a href=\"http:\/\/iot.tfeya.ru\/\" target=\"_blank\" rel=\"noreferrer noopener\"><code>iot.tfeya.ru<\/code><\/a>).<\/li>\n\n\n\n<li>\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0435&nbsp;<strong>Cron<\/strong>&nbsp;\u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u0436\u0434\u044b\u0435 30 \u043c\u0438\u043d\u0443\u0442:&nbsp;<code>*\/30 * * * * \/usr\/bin\/php \/var\/www\/iot.tfeya.ru\/auto_watering.php &gt;&gt; \/var\/log\/watering.log<\/code><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412\u0441\u0451. \u0412\u0430\u0448 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u0434\u0430\u0442\u0447\u0438\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%90_%D1%87%D1%82%D0%BE_%D0%BD%D0%B0%D1%81%D1%87%D0%B5%D1%82_%D0%BA%D1%80%D0%B0%D1%81%D0%B8%D0%B2%D0%BE%D0%B3%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%B0\"><\/span>\u0410 \u0447\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 cron \u2014 \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0437\u0430\u0439\u0442\u0438 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0438\u043b\u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u041d\u043e \u0435\u0441\u043b\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043d\u043e \u043f\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c \u0438\u0433\u0440\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u0430\u043c\u043e\u0433\u043e \u042f\u043d\u0434\u0435\u043a\u0441\u0430, \u0442\u043e \u043d\u0430 \u0412\u0430\u0448\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u0430\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u0418 \u043f\u043e\u043b\u043d\u0430\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u0430 \u043f\u043e \u0434\u0438\u0437\u0430\u0439\u043d\u0443 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0438 \u0412\u0430\u0448\u0435\u0433\u043e \u0423\u043c\u043d\u043e\u0433\u043e \u0414\u043e\u043c\u0430.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412\u044b\u0448\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439&nbsp;<strong>SPA-\u0434\u0430\u0448\u0431\u043e\u0440\u0434 \u043d\u0430 PHP + Tailwind CSS<\/strong>&nbsp;(\u0432 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435), \u043a\u043e\u0442\u043e\u0440\u044b\u0439:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u041f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 OAuth-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u042f\u043d\u0434\u0435\u043a\u0441\u0430.<\/li>\n\n\n\n<li>\u041c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e (\u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b) \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f&nbsp;<code>curl_multi<\/code>&nbsp;\u0434\u043b\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0436\u0434\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u0430 10 \u0441\u0435\u043a\u0443\u043d\u0434).<\/li>\n\n\n\n<li>\u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c\/\u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043f\u0440\u0438\u0431\u043e\u0440\u044b, \u043c\u0435\u043d\u044f\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c \u043b\u0430\u043c\u043f \u0438 \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0443 \u043e\u0431\u043e\u0433\u0440\u0435\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/li>\n\n\n\n<li>\u041a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f&nbsp;<code>offline<\/code>&nbsp;\u0438&nbsp;<code>retrievable: false<\/code>, \u043d\u0435 \u0432\u0432\u043e\u0434\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0437\u0430\u0431\u043b\u0443\u0436\u0434\u0435\u043d\u0438\u0435.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><em>\u041a\u043e\u0434 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u044b\u043c \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438, \u043d\u043e \u043e\u043d \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0433\u043e\u0442\u043e\u0432 \u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e. \u0415\u0441\u043b\u0438 \u0442\u0435\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443, \u044f \u0441 \u0440\u0430\u0434\u043e\u0441\u0442\u044c\u044e \u0432\u044b\u043b\u043e\u0436\u0443 \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043d\u0430 GitHub \u0438\u043b\u0438 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(\u0421\u043f\u043e\u0439\u043b\u0435\u0440: \u043a\u043b\u044e\u0447 \u043a \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435&nbsp;<\/em><code><em>session_write_close()<\/em><\/code><em>&nbsp;\u043f\u0435\u0440\u0435\u0434 AJAX-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0432 PHP \u0438 &#171;\u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0435&#187; \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 UI \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 JavaScript, \u043e \u0447\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u0445 \u043f\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439).<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D1%8D%D1%82%D0%BE_%D0%BB%D1%83%D1%87%D1%88%D0%B5_%D1%87%D0%B5%D0%BC_%C2%AB%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE_%D0%BA%D1%83%D0%BF%D0%B8%D1%82%D1%8C_%D0%B2%D1%81%D1%91_%D0%B3%D0%BE%D1%82%D0%BE%D0%B2%D0%BE%D0%B5%C2%BB\"><\/span>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0435, \u0447\u0435\u043c \u00ab\u043f\u0440\u043e\u0441\u0442\u043e \u043a\u0443\u043f\u0438\u0442\u044c \u0432\u0441\u0451 \u0433\u043e\u0442\u043e\u0432\u043e\u0435\u00bb?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u0421\u0432\u043e\u0431\u043e\u0434\u0430 \u043b\u043e\u0433\u0438\u043a\u0438.<\/strong>&nbsp;\u0412\u044b \u043d\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u042f\u043d\u0434\u0435\u043a\u0441\u0430. \u0425\u043e\u0442\u0438\u0442\u0435 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u0432\u0435\u0442, \u0435\u0441\u043b\u0438 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u044c &lt; 20%, \u0418 \u043d\u0430 \u0443\u043b\u0438\u0446\u0435 \u0442\u0435\u043c\u043d\u043e (\u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0433\u043e Weather API), \u0418 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043d\u0435 \u0432\u0442\u043e\u0440\u043d\u0438\u043a? \u041d\u0430 PHP \u044d\u0442\u043e 5 \u0441\u0442\u0440\u043e\u0447\u0435\u043a \u043a\u043e\u0434\u0430.<\/li>\n\n\n\n<li><strong>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c.<\/strong>&nbsp;\u041d\u0430 \u043e\u0434\u043d\u043e\u043c \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u042f\u043d\u0434\u0435\u043a\u0441\u0430, \u0434\u0430\u0442\u0447\u0438\u043a\u0438 Sensorbox, \u043a\u0430\u043c\u0435\u0440\u044b Xiaomi \u0438 \u0440\u0435\u043b\u0435, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 MQTT. \u0412\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u2014 \u044d\u0442\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0447\u0438\u043a.<\/li>\n\n\n\n<li><strong>\u041d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c.<\/strong>&nbsp;\u0415\u0441\u043b\u0438 \u0437\u0430\u0432\u0442\u0440\u0430 \u042f\u043d\u0434\u0435\u043a\u0441 \u0438\u0437\u043c\u0435\u043d\u0438\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0438\u043b\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u044b, \u0432\u0430\u0448\u0430 \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0430\u0448\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/li>\n\n\n\n<li><strong>\u042d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e.<\/strong>&nbsp;\u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 \u0432\u044b\u0448\u0435, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0434\u0432\u0443\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c:&nbsp;<code>file_get_contents()<\/code>&nbsp;\u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438&nbsp;<code>curl<\/code>&nbsp;\u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438. \u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%97%D0%B0%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5\"><\/span>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c DIY \u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043a\u0430\u043a \u0432\u0440\u0430\u0433\u043e\u0432. \u041e\u043d\u0438 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430. \u042f\u043d\u0434\u0435\u043a\u0441 \u0434\u0430\u0435\u0442 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0435, \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 &#171;\u0436\u0435\u043b\u0435\u0437\u043e&#187; (\u0440\u043e\u0437\u0435\u0442\u043a\u0438, \u0440\u0435\u043b\u0435), \u0430 \u0432\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442, \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u00ab\u043c\u043e\u0441\u0442\u00bb. \u0412\u044b \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u0441\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0449\u043d\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u0442\u044c \u0432\u0430\u0448 \u0443\u043c\u043d\u044b\u0439 \u0434\u043e\u043c, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0435\u0442\u0435 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0438 \u0441\u0442\u0430\u043d\u0435\u0442\u0435 \u0435\u0433\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u043e\u043c.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/yandex.ru\/dev\/id\/doc\/ru\/\" target=\"_blank\" rel=\"noreferrer noopener\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u042f\u043d\u0434\u0435\u043a\u0441 ID (OAuth)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/yandex.ru\/dev\/dialogs\/smart-home\/doc\/ru\/concepts\/platform-protocol\" target=\"_blank\" rel=\"noreferrer noopener\">\u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u042f\u043d\u0434\u0435\u043a\u0441.\u0423\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/habr.com\/ru\/articles\/789200\/\">\u0421\u0442\u0430\u0442\u044c\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435 \u0445\u0432\u0430\u0442\u0438\u043b\u043e<\/a><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><em>P.S. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 OAuth \u0438\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043f\u043e\u043b\u0437\u0443\u043d\u043a\u043e\u0432 \u044f\u0440\u043a\u043e\u0441\u0442\u0438 \u0438 \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440 \u2014 \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0418\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0433\u0438\u0431\u0440\u0438\u0434\u043d\u044b\u0439 \u0443\u043c\u043d\u044b\u0439 \u0434\u043e\u043c \u2014 \u044d\u0442\u043e \u043d\u0435 \u00ab\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u0435 \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430\u00bb, \u0430 \u0430\u043f\u0433\u0440\u0435\u0439\u0434 \u0435\u0433\u043e \u0434\u043e \u0432\u043d\u0435\u0434\u043e\u0440\u043e\u0436\u043d\u0438\u043a\u0430. \u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u0438\u0441\u043f\u043b\u0435\u0439, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043e\u0442 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0438\u043b\u0438 \u0421\u0431\u0435\u0440\u0430, \u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0447\u0435\u0440\u0435\u0437 API \u0441\u0447\u0438\u0442\u0430\u043d\u044b \u0443\u043c\u043d\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u044b \u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u0432\u043a\u043b \/ \u0432\u044b\u043a\u043b). [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1102,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"dsgo_overlay_header":false,"dsgo_overlay_header_text_color":"","dsgo_overlay_skip_top_bar":false,"_designsetgo_exclude_llms":false,"footnotes":""},"categories":[1,12,104],"tags":[346,255,365,253,362],"class_list":["post-1099","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-1","category-12","category-104","tag-diy","tag-255","tag-365","tag-253","tag-362"],"aioseo_notices":[],"tf_views":0,"tf_read_time":27,"_links":{"self":[{"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts\/1099","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1099"}],"version-history":[{"count":2,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts\/1099\/revisions"}],"predecessor-version":[{"id":1104,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts\/1099\/revisions\/1104"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/media\/1102"}],"wp:attachment":[{"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1099"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1099"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}