{"id":1106,"date":"2026-08-01T23:26:32","date_gmt":"2026-08-01T20:26:32","guid":{"rendered":"https:\/\/news.tfeya.ru\/?p=1106"},"modified":"2026-08-01T23:26:36","modified_gmt":"2026-08-01T20:26:36","slug":"php-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80-%d0%b4%d0%bb%d1%8f-iot-%d0%ba%d0%b0%d0%ba-%d1%8f-%d0%bf%d0%b8%d1%81%d0%b0%d0%bb-%d0%b4%d0%b0%d1%88%d0%b1%d0%be%d1%80%d0%b4-%d0%b4%d0%bb%d1%8f-%d1%83%d0%bc","status":"publish","type":"post","link":"https:\/\/news.tfeya.ru\/?p=1106","title":{"rendered":"PHP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043b\u044f IoT: \u043a\u0430\u043a \u044f \u043f\u0438\u0441\u0430\u043b \u0434\u0430\u0448\u0431\u043e\u0440\u0434 \u0434\u043b\u044f \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u0438 \u0441\u043e\u0431\u0440\u0430\u043b \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0433\u0440\u0430\u0431\u043b\u0438"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u041f\u0440\u0438\u0432\u0435\u0442.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u0440\u0430\u0437\u0443 \u0441\u043a\u0430\u0436\u0443: \u044f \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043d\u043e \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u0435\u0449\u0435 \u0441 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0430 \u0443 \u043c\u0435\u043d\u044f \u0432\u044b\u043b\u0435\u0442\u0430\u043b\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0448\u0438\u0431\u043e\u043a, \u0447\u0442\u043e \u0438\u0445 \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u0438 \u043f\u043e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0443 \u0434\u0430\u0436\u0435 \u043e\u0434\u043d\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0437\u0430\u0441\u0438\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u043d\u0430 \u043e\u0434\u0438\u043d \u0432\u0435\u0447\u0435\u0440 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0433\u0443\u043b\u044f\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u044f \u0432\u043e\u043e\u0431\u0449\u0435 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u043b \u0434\u0430\u043b\u0435\u043a \u043e\u0442 IT. \u0418, \u043a\u043e\u0433\u0434\u0430 \u044f \u0432\u043e\u0448\u0435\u043b \u0432 \u044d\u0442\u0443 \u043e\u0431\u043b\u0430\u0441\u0442\u044c, \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0441\u044b\u043f\u0430\u043b\u0438\u0441\u044c \u2013 \u043c\u044b\u0441\u043b\u0438\u043b \u044f \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0438 \u0431\u044b\u043b \u043e\u0447\u0435\u043d\u044c \u0443\u0437\u043a\u043e\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0436\u0435\u043b\u0435\u0437\u043e \u0438 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u0438\u043a\u0443. \u0422\u0435\u043f\u0435\u0440\u044c \u0436\u0435 \u0432\u0441\u0435 \u0447\u0443\u0442\u044c \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u0445\u043e\u0431\u0431\u0438 \u2014 \u044f \u0434\u0435\u043b\u0430\u044e \u0440\u0430\u0437\u043d\u044b\u0435 \u0436\u0435\u043b\u0435\u0437\u043a\u0438 \u0434\u043b\u044f \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430. \u041d\u0443 \u0438 \u043a\u0430\u043a \u0443 \u043b\u044e\u0431\u043e\u0433\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430, \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u0440\u043e\u0437\u0435\u0442\u043a\u0438 \u042f\u043d\u0434\u0435\u043a\u0441, \u043b\u0430\u043c\u043f\u043e\u0447\u043a\u0438, \u0438 \u043a\u0443\u0447\u0430 \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u043d\u0430 ESP8266 \u0438 ESP32.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0418 \u0432\u043e\u0442 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u043c\u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u0432\u0435\u0449\u044c: \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0440\u043e\u0437\u0435\u0442\u043a\u043e\u0439 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0438\u0439 \u043c\u043e\u0435\u0433\u043e \u0441\u0430\u043c\u043e\u043f\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b. \u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430. \u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u044f \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u044f \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e PHP \u2014 \u044d\u0442\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u201c\u0441\u0430\u0439\u0442\u043e\u0432-\u0432\u0438\u0437\u0438\u0442\u043e\u043a\u201d. \u0418 \u0437\u0430\u043e\u0434\u043d\u043e \u044f \u0441\u043e\u0431\u0440\u0430\u043b \u0442\u0430\u043a\u043e\u0439 \u0431\u0443\u043a\u0435\u0442 \u0433\u0440\u0430\u0431\u043b\u0435\u0439, \u0447\u0442\u043e \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431 \u044d\u0442\u043e\u043c \u0441\u0442\u0430\u0442\u044c\u044e, \u0447\u0442\u043e\u0431\u044b \u043a\u0442\u043e-\u0442\u043e \u043d\u0435 \u043d\u0430\u0441\u0442\u0443\u043f\u0430\u043b \u043d\u0430 \u0442\u0435 \u0436\u0435.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041c\u043e\u0436\u043d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Home Assistant \u0438 ESPHome, \u0430 \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c Opensource-\u043f\u0440\u043e\u0435\u043a\u0442\u044b&#8230; \u041d\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u0438\u0437 \u043d\u0430c, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u0432 \u043f\u043e \u0436\u0435\u043b\u0435\u0437\u0443, \u0447\u0430\u0441\u0442\u043e \u043a\u043e\u0434\u044f\u0442 \u0432 \u0431\u043b\u043e\u043a\u043d\u043e\u0442\u0438\u043a\u0435 \u0432 Linux, \u0440\u0443\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044f GCC \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440, \u0442\u0430\u043a \u0432\u043e\u0442&#8230; \u041f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u043d\u0430 PHP \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0443\u0447\u0435\u0441\u0442\u044c \u0438 \u043e\u0441\u043e\u0437\u043d\u0430\u0442\u044c \u043d\u044e\u0430\u043d\u0441\u044b \u043f\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043e\u0442\u043a\u0443\u0434\u0430 \u0438 \u043f\u043e\u0442\u043e\u043c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043e\u043f\u0435\u043d\u0441\u043e\u0440\u0441\u0435\u0440\u0430\u043c\u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u043f\u043e\u0432\u0441\u0435\u043c\u0435\u0441\u0442\u043d\u043e\u0435 \u0438 \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0438\u0435 \u043c\u0430\u0448\u0438\u043d, \u043a\u0430\u043a \u0432 \u0444\u0438\u043b\u044c\u043c\u0435 \u0420\u043e\u0431\u043e\u0442 2, \u043a\u043e\u0433\u0434\u0430 \u0441\u0442\u0430\u0440\u043e\u0433\u043e \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u043e\u0440\u0430 \u043f\u0440\u0435\u0441\u0441\u043e\u0432\u0430\u043b, \u0430 \u0437\u0430\u0442\u0435\u043c \u0443\u0431\u0438\u043b \u0418\u0418.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>\u0418\u0442\u0430\u043a, \u043f\u043e\u0433\u043d\u0430\u043b\u0438.&nbsp;<\/em><\/strong>\u041d\u043e \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0434\u0435\u043b\u0430\u044e \u0443\u043f\u043e\u0440 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u0442\u0435 \u0441\u0430\u043c\u044b\u0435 \u0437\u0430\u0432\u0435\u0442\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u043d\u044c\u0448\u0435 \u043d\u0430\u0434\u043e \u0431\u044b\u043b\u043e \u0432\u0435\u0447\u0435\u0440\u0430\u043c\u0438 \u0433\u0443\u0433\u043b\u0438\u0442\u044c \u0433\u0434\u0435-\u0442\u043e \u043d\u0430 StackOverflow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0417\u0430\u0434\u0430\u0447\u0430:&nbsp;<\/strong>\u0438\u043c\u0435\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \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 \u0423\u043c\u043d\u044b\u0439 \u0414\u043e\u043c \u042f\u043d\u0434\u0435\u043a\u0441\u0430, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432 \u044d\u0442\u043e\u043c \u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0443\u0437\u043a\u0438\u0439 \u043a\u0435\u0439\u0441&nbsp;<\/strong>\u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0437\u0430\u0434\u0430\u0447\u0438: \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0438 \u043f\u043e\u0440\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441 \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0435 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0443\u043c\u043d\u0443\u044e \u0440\u043e\u0437\u0435\u0442\u043a\u0443, \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432 \u042f\u043d\u0434\u0435\u043a\u0441, \u0434\u043b\u044f \u043f\u043e\u043b\u0438\u0432\u0430 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f.\u0414\u043b\u044f \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442\u0438: \u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u0435\u0439\u0441 \u044f \u0443\u0436\u0435 \u0440\u0435\u0448\u0438\u043b, \u043d\u043e&#8230;.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0422\u043e \u0435\u0441\u0442\u044c \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u043d\u0430 \u043f\u043e\u0434\u043e\u043a\u043e\u043d\u043d\u0438\u043a\u0435 \u0447\u0442\u043e-\u0442\u043e \u0442\u0438\u043f\u0430 &#171;\u0423\u043c\u043d\u043e\u0433\u043e \u043e\u0433\u043e\u0440\u043e\u0434\u0430&#187;, \u0433\u0434\u0435 \u0440\u0430\u0441\u0442\u0435\u043d\u0438\u044f\u043c \u0447\u0430\u0441\u0442\u043e \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0432\u043e\u0434\u044b, \u043a\u043e\u0433\u0434\u0430 \u044f \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0435.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/743\/7e5\/da1\/7437e5da18cf626a3299c6c4aec2a752.png\" alt=\"\u0414\u0430\u0442\u0447\u0438\u043a \u0432\u043b\u0430\u0433\u0438 \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u0441\u0443\u0445\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b\" title=\"\u0414\u0430\u0442\u0447\u0438\u043a \u0432\u043b\u0430\u0433\u0438 \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u0441\u0443\u0445\u043e\u0441\u0442\u0438 \u043f\u043e\u0447\u0432\u044b\"\/><figcaption class=\"wp-element-caption\">\u0414\u0430\u0442\u0447\u0438\u043a \u0432\u043b\u0430\u0433\u0438 \u0434\u043b\u044f \u043e\u0446\u0435\u043d\u043a\u0438 \u0441\u0443\u0445\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\/4a3\/ab0\/ec1\/4a3ab0ec15d94eab7b653d13e404f434.jpg\" alt=\"\u0411\u0430\u0434\u044c\u044f \u0441 \u0432\u043e\u0434\u043e\u0439, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0442\u043e\u0440, \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=\"\u0411\u0430\u0434\u044c\u044f \u0441 \u0432\u043e\u0434\u043e\u0439, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0442\u043e\u0440, \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\">\u0411\u0430\u0434\u044c\u044f \u0441 \u0432\u043e\u0434\u043e\u0439, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0442\u043e\u0440, \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\">\u0415\u0441\u0442\u044c \u043a\u0443\u0447\u0430 \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u043e\u043a \u043d\u0430 ESP32 \u0438 \u0435\u0441\u0442\u044c \u0443\u043c\u043d\u0430\u044f \u0440\u043e\u0437\u0435\u0442\u043a\u0430 \u0437\u0430 370 \u0440\u0443\u0431\u043b\u0435\u0439.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a53\/b7a\/6b5\/a53b7a6b5cab7b99e98aaa71c8f69109.jpg\" alt=\"Sensorbox \u043a\u0430\u043a \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\" title=\"Sensorbox \u043a\u0430\u043a \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\"\/><figcaption class=\"wp-element-caption\">Sensorbox \u043a\u0430\u043a \u0441\u0430\u043c\u043e\u0434\u0435\u043b\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u043d\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\u042f \u043d\u0435 \u0445\u043e\u0447\u0443 \u0432\u044b\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u043c\u0430\u0433\u0430\u0437\u0438\u043d \u0437\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 \u0438\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u0430 \u0445\u043e\u0447\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043e\u0434\u043d\u043e\u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 \u0441\u0432\u043e\u0435\u043c \u043d\u043e\u0443\u0442\u0435 \u043d\u0430 \u0445\u043e\u043b\u043e\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0442\u0430\u043a \u0432\u0441\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0440\u0430\u0446\u0438\u043e\u043d \u043c\u043e\u0435\u0433\u043e \u043f\u0438\u0442\u0430\u043d\u0438\u044f.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e39\/a25\/467\/e39a2546786cafd43d86fa2942986bca.jpg\" alt=\"\u0414\u0438\u0441\u043f\u043b\u0435\u0439 \u043d\u0430 \u043c\u043e\u0435\u043c \u0445\u043e\u043b\u043e\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0435\" title=\"\u0414\u0438\u0441\u043f\u043b\u0435\u0439 \u043d\u0430 \u043c\u043e\u0435\u043c \u0445\u043e\u043b\u043e\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0435\"\/><figcaption class=\"wp-element-caption\">\u0414\u0438\u0441\u043f\u043b\u0435\u0439 \u043d\u0430 \u043c\u043e\u0435\u043c \u0445\u043e\u043b\u043e\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0435<\/figcaption><\/figure>\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=1106\/#%D0%97%D0%B0%D1%87%D0%B5%D0%BC_%D0%B2%D0%BE%D0%BE%D0%B1%D1%89%D0%B5_PHP_%D0%B4%D0%BB%D1%8F_%D0%B6%D0%B5%D0%BB%D0%B5%D0%B7%D0%B0\" >\u0417\u0430\u0447\u0435\u043c \u0432\u043e\u043e\u0431\u0449\u0435 PHP \u0434\u043b\u044f \u0436\u0435\u043b\u0435\u0437\u0430?<\/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=1106\/#%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D0%BF%D0%B5%D1%80%D0%B2%D0%B0%D1%8F_%E2%80%9C%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D0%BE%D0%BD%D0%BE_%D0%B2%D0%B8%D1%81%D0%BD%D0%B5%D1%82%E2%80%9D\" >\u0413\u0440\u0430\u0431\u043b\u044f \u043f\u0435\u0440\u0432\u0430\u044f: \u201c\u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u043d\u043e \u0432\u0438\u0441\u043d\u0435\u0442?!\u201d<\/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=1106\/#%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D0%B2%D1%82%D0%BE%D1%80%D0%B0%D1%8F_%E2%80%9C%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D1%82%D0%B0%D0%BA_%D0%B4%D0%BE%D0%BB%D0%B3%D0%BE%E2%80%9D\" >\u0413\u0440\u0430\u0431\u043b\u044f \u0432\u0442\u043e\u0440\u0430\u044f: \u201c\u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a \u0434\u043e\u043b\u0433\u043e?!\u201d<\/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=1106\/#%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D1%82%D1%80%D0%B5%D1%82%D1%8C%D1%8F_%E2%80%9CCannot_read_properties_of_null%E2%80%9D\" >\u0413\u0440\u0430\u0431\u043b\u044f \u0442\u0440\u0435\u0442\u044c\u044f: \u201cCannot read properties of null\u201d<\/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=1106\/#%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D1%87%D0%B5%D1%82%D0%B2%D0%B5%D1%80%D1%82%D0%B0%D1%8F_%E2%80%9C%D0%AF_%D0%BD%D0%B0%D0%B6%D0%B0%D0%BB_%D0%BA%D0%BD%D0%BE%D0%BF%D0%BA%D1%83_%D0%B0_%D0%BE%D0%BD%D0%BE_%D0%BD%D0%B5_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82%E2%80%9D\" >\u0413\u0440\u0430\u0431\u043b\u044f \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f: \u201c\u042f \u043d\u0430\u0436\u0430\u043b \u043a\u043d\u043e\u043f\u043a\u0443, \u0430 \u043e\u043d\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442!\u201d<\/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=1106\/#%D0%A7%D1%82%D0%BE_%D0%B2_%D0%B8%D1%82%D0%BE%D0%B3%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D0%BB%D0%BE%D1%81%D1%8C\" >\u0427\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c<\/a><\/li><\/ul><\/nav><\/div>\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%97%D0%B0%D1%87%D0%B5%D0%BC_%D0%B2%D0%BE%D0%BE%D0%B1%D1%89%D0%B5_PHP_%D0%B4%D0%BB%D1%8F_%D0%B6%D0%B5%D0%BB%D0%B5%D0%B7%D0%B0\"><\/span>\u0417\u0430\u0447\u0435\u043c \u0432\u043e\u043e\u0431\u0449\u0435 PHP \u0434\u043b\u044f \u0436\u0435\u043b\u0435\u0437\u0430?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u044a\u044f\u0441\u043d\u044e, \u043f\u043e\u0447\u0435\u043c\u0443 \u044f \u043d\u0435 \u043f\u043e\u0448\u0435\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u043f\u0443\u0442\u0435\u043c.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u043f\u0435\u0440\u0432\u044b\u0439:&nbsp;<\/strong>Home Assistant. \u041c\u043e\u0449\u043d\u0430\u044f \u0448\u0442\u0443\u043a\u0430, \u043d\u043e \u0434\u043b\u044f \u043c\u043e\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u044d\u0442\u043e \u043a\u0430\u043a \u0438\u0437 \u043f\u0443\u0448\u043a\u0438 \u043f\u043e \u0432\u043e\u0440\u043e\u0431\u044c\u044f\u043c. \u041c\u043d\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d MQTT, Node-RED, Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0438 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0423 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u0441\u0435\u0440\u0432\u0435\u0440, \u043e\u0434\u0438\u043d \u0434\u0430\u0442\u0447\u0438\u043a \u0438 \u043e\u0434\u043d\u0430 \u0440\u043e\u0437\u0435\u0442\u043a\u0430. \u0420\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0434\u0438 \u044d\u0442\u043e\u0433\u043e \u0446\u0435\u043b\u044b\u0439 \u0437\u043e\u043e\u043f\u0430\u0440\u043a \u2014 overkill.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0432\u0442\u043e\u0440\u043e\u0439:&nbsp;<\/strong>Python-\u0441\u043a\u0440\u0438\u043f\u0442. \u0422\u043e\u0436\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0443\u0436\u0435 \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f PHP (\u043f\u0435\u0442-\u0441\u0430\u0439\u0442 \u043c\u043e\u0435\u0439 \u043a\u043e\u0448\u043a\u0438 (\u0448\u0443\u0447\u0443)).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0442\u0440\u0435\u0442\u0438\u0439: \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430 PHP. \u0414\u0430, \u0434\u0430, \u0442\u043e\u043c \u0441\u0430\u043c\u043e\u043c PHP, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u201c\u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u043e\u0432\u201d. \u041d\u043e \u0432\u0435\u0434\u044c PHP \u0443\u043c\u0435\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0447\u0435\u0440\u0435\u0437 curl, \u0443\u043c\u0435\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 JSON, \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043f\u043e cron. \u0427\u0435\u0433\u043e \u0435\u0449\u0435 \u043d\u0430\u0434\u043e? \u0418 \u0432\u043e\u0442 \u044f \u0441\u0435\u043b \u043f\u0438\u0441\u0430\u0442\u044c. \u0418 \u0442\u0443\u0442 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c\u2026<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D0%BF%D0%B5%D1%80%D0%B2%D0%B0%D1%8F_%E2%80%9C%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D0%BE%D0%BD%D0%BE_%D0%B2%D0%B8%D1%81%D0%BD%D0%B5%D1%82%E2%80%9D\"><\/span>\u0413\u0440\u0430\u0431\u043b\u044f \u043f\u0435\u0440\u0432\u0430\u044f: \u201c\u041f\u043e\u0447\u0435\u043c\u0443 \u043e\u043d\u043e \u0432\u0438\u0441\u043d\u0435\u0442?!\u201d<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u2014 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 API \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u044e \u2014 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u044e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u2014 \u0433\u0440\u0443\u0437\u0438\u0442\u0441\u044f \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u0442\u0440\u0438. \u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0434\u0443\u043c\u0430\u044e.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u043e\u0442\u043e\u043c \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c AJAX-\u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0447\u0442\u043e\u0431\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0430\u043b\u0430\u0441\u044c \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043b\u0438\u043a\u0435. \u0418 \u0442\u0443\u0442 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0432\u0435\u0441\u0435\u043b\u044c\u0435. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u044e \u0434\u0432\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 \u2014 \u0432\u0442\u043e\u0440\u0430\u044f \u0432\u0438\u0441\u043d\u0435\u0442. \u041d\u0430\u0436\u0438\u043c\u0430\u044e \u201c\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c\u201d \u2014 \u0432\u0438\u0441\u043d\u0435\u0442 \u043d\u0430 10 \u0441\u0435\u043a\u0443\u043d\u0434. \u0427\u0442\u043e \u0437\u0430 \u0445\u0440\u0435\u043d\u044c? \u0427\u0430\u0441 \u0433\u0443\u0433\u043b\u0435\u043d\u0438\u044f, \u0438 \u044f \u043d\u0430\u0445\u043e\u0436\u0443 \u043e\u0442\u0432\u0435\u0442: \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430 \u0441\u0435\u0441\u0441\u0438\u0439 \u0432 PHP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0442\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0448\u044c session_start(), PHP \u0441\u0442\u0430\u0432\u0438\u0442 \u044d\u043a\u0441\u043a\u043b\u044e\u0437\u0438\u0432\u043d\u044b\u0439 \u043b\u043e\u043a \u043d\u0430 \u0444\u0430\u0439\u043b \u0441\u0435\u0441\u0441\u0438\u0438. \u0418 \u043f\u043e\u043a\u0430 \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f (\u0438\u043b\u0438 \u043d\u0435 \u0437\u0430\u043a\u0440\u043e\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u044e \u0432\u0440\u0443\u0447\u043d\u0443\u044e), \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0443 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u043e\u044f\u0442\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0438 \u0436\u0434\u0430\u0442\u044c. \u0423 \u043c\u0435\u043d\u044f \u0436\u0435 AJAX \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e: \u043e\u0434\u0438\u043d \u0442\u044f\u043d\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432, \u0434\u0440\u0443\u0433\u043e\u0439 \u2014 \u0438\u0445 \u0441\u0442\u0430\u0442\u0443\u0441\u044b. \u0418 \u043e\u043d\u0438 \u0436\u0434\u0443\u0442 \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430, \u043a\u0430\u043a \u043d\u0430 \u0443\u0437\u043a\u043e\u0439 \u0442\u0440\u043e\u043f\u0438\u043d\u043a\u0435. \u0420\u0435\u0448\u0435\u043d\u0438\u0435: \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u0447\u043a\u0430 \u043a\u043e\u0434\u0430.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\n$token = $_SESSION&#x5B;&#039;yandex_token&#039;]; \nsession_write_close(); \/\/ \u0412\u0441\u0451, \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u043b\u0438 \u0441\u0435\u0441\u0441\u0438\u044e\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D0%B2%D1%82%D0%BE%D1%80%D0%B0%D1%8F_%E2%80%9C%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D1%82%D0%B0%D0%BA_%D0%B4%D0%BE%D0%BB%D0%B3%D0%BE%E2%80%9D\"><\/span>\u0413\u0440\u0430\u0431\u043b\u044f \u0432\u0442\u043e\u0440\u0430\u044f: \u201c\u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a \u0434\u043e\u043b\u0433\u043e?!\u201d<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u041b\u0430\u0434\u043d\u043e, \u0441\u0435\u0441\u0441\u0438\u0438 \u043f\u043e\u0447\u0438\u043d\u0438\u043b. \u0422\u0435\u043f\u0435\u0440\u044c \u0445\u043e\u0447\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441\u044b \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u0423 \u043c\u0435\u043d\u044f \u0438\u0445 11 \u0448\u0442\u0443\u043a.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043c\u043e\u0442\u0440\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u042f\u043d\u0434\u0435\u043a\u0441\u0430: \u0435\u0441\u0442\u044c \u043c\u0430\u0441\u0441\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \/user\/devices\/query, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441\u044b \u0432\u0441\u0435\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0441\u0440\u0430\u0437\u0443. \u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0434\u0435\u043b\u0430\u044e \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441. \u041d\u043e!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u042f\u043d\u0434\u0435\u043a\u0441 \u0438\u043d\u043e\u0433\u0434\u0430 \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441\u044b \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0438\u043b\u0438 \u0443\u0448\u043b\u0438 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0433\u043e\u0432\u043e\u0440\u0438\u0442: \u201c\u0417\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0439\u0442\u0435 \u0442\u0430\u043a\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0447\u0435\u0440\u0435\u0437 \/devices\/{id}\u201d. \u041e\u043a\u0435\u0439, \u0434\u0435\u043b\u0430\u044e \u0446\u0438\u043a\u043b:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nforeach ($devices as $dev) { \n  $status = apiRequest(&quot;\/devices\/{$dev&#x5B;&#039;id&#039;]}&quot;);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u044e. \u0416\u0434\u0443. \u0416\u0434\u0443. \u0416\u0434\u0443. 15 \u0441\u0435\u043a\u0443\u043d\u0434 \u0433\u0440\u0443\u0437\u0438\u0442\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430. \u0411\u0435\u0441\u0438\u0442. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044f \u0434\u0435\u043b\u0430\u044e 11 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u041a\u0430\u0436\u0434\u044b\u0439 \u0436\u0434\u0435\u0442, \u043f\u043e\u043a\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u0441\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0420\u0435\u0448\u0435\u043d\u0438\u0435:&nbsp;<\/strong>curl_multi_init. \u042d\u0442\u043e \u0442\u0430\u043a\u0430\u044f \u0448\u0442\u0443\u043a\u0430 \u0432 PHP, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e. \u041d\u0430\u043f\u0438\u0441\u0430\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u044e:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nfunction apiRequestParallel($urls, $headers) { \n  $mh = curl_multi_init(); \n  foreach ($urls as $url) { \n    $ch = curl_init($url); \/\/ ... \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 ... \n    curl_multi_add_handle($mh, $ch); \n  } \n  $running = null; \n  do { curl_multi_exec($mh, $running); } while ($running &gt; 0); \/\/ \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u0412\u043c\u0435\u0441\u0442\u043e 15 \u0441\u0435\u043a\u0443\u043d\u0434 \u2014 2 \u0441\u0435\u043a\u0443\u043d\u0434\u044b. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043b\u0435\u0442\u044f\u0442 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D1%82%D1%80%D0%B5%D1%82%D1%8C%D1%8F_%E2%80%9CCannot_read_properties_of_null%E2%80%9D\"><\/span>\u0413\u0440\u0430\u0431\u043b\u044f \u0442\u0440\u0435\u0442\u044c\u044f: \u201cCannot read properties of null\u201d<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u0434\u0435\u043b\u0430\u043b \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432. \u0412\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0440\u0430\u0434\u0443\u044e\u0441\u044c.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u043e\u0442\u043e\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e \u043d\u043e\u0432\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u2014 \u0431\u0435\u043b\u044b\u0439 \u044d\u043a\u0440\u0430\u043d. \u0412 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043e\u0448\u0438\u0431\u043a\u0430:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Cannot read properties of null (reading \u2018value\u2019)<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043c\u043e\u0442\u0440\u044e \u043a\u043e\u0434 JavaScript:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nconst isOn = onCap.state.value;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u0427\u0442\u043e \u043d\u0435 \u0442\u0430\u043a-\u0442\u043e?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0410 \u0442\u043e, \u0447\u0442\u043e API \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0438\u043d\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 null \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 state. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u043d\u043e\u0432\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438\u043b\u0438 \u0442\u0435\u0445, \u0447\u0442\u043e \u0443\u0448\u043b\u0438 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u042f-\u0442\u043e \u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e API \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0410 \u043e\u043d, \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043c\u043e\u0436\u0435\u0442 \u0438 null \u043f\u043e\u0434\u043a\u0438\u043d\u0443\u0442\u044c.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0420\u0435\u0448\u0435\u043d\u0438\u0435:&nbsp;<\/strong>Optional Chaining \u0432 JavaScript.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\nconst capState = onCap?.state || {}; \nconst isOn = capState.value || false;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u0422\u0435\u043f\u0435\u0440\u044c \u0435\u0441\u043b\u0438 state \u0440\u0430\u0432\u0435\u043d null, \u043a\u043e\u0434 \u043d\u0435 \u043f\u0430\u0434\u0430\u0435\u0442, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u201c\u0421\u0442\u0430\u0442\u0443\u0441 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d\u201d. \u0418 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043d\u0435 \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0417\u0430\u043e\u0434\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0435 \u0431\u0435\u0439\u0434\u0436\u0438: \u201c\u041d\u0435 \u0432 \u0441\u0435\u0442\u0438\u201d, \u201c\u0423\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\u201d, \u201c\u0421\u0442\u0430\u0442\u0443\u0441 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d\u201d. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0440\u0430\u0437\u0443 \u0432\u0438\u0434\u0438\u0442, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442, \u0430 \u043d\u0435 \u0433\u0430\u0434\u0430\u0435\u0442, \u043f\u043e\u0447\u0435\u043c\u0443 \u0440\u043e\u0437\u0435\u0442\u043a\u0430 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D1%8F_%D1%87%D0%B5%D1%82%D0%B2%D0%B5%D1%80%D1%82%D0%B0%D1%8F_%E2%80%9C%D0%AF_%D0%BD%D0%B0%D0%B6%D0%B0%D0%BB_%D0%BA%D0%BD%D0%BE%D0%BF%D0%BA%D1%83_%D0%B0_%D0%BE%D0%BD%D0%BE_%D0%BD%D0%B5_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82%E2%80%9D\"><\/span>\u0413\u0440\u0430\u0431\u043b\u044f \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f: \u201c\u042f \u043d\u0430\u0436\u0430\u043b \u043a\u043d\u043e\u043f\u043a\u0443, \u0430 \u043e\u043d\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442!\u201d<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u0430\u043c\u0430\u044f \u0431\u0435\u0441\u044f\u0447\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c (\u0442\u043e \u0435\u0441\u0442\u044c \u044f) \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u0442 \u201c\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u201d. \u0412\u0438\u0434\u0438\u0442 \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438. \u0416\u0434\u0435\u0442 2 \u0441\u0435\u043a\u0443\u043d\u0434\u044b.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u201c\u0412\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043e\u201d. \u0427\u0442\u043e \u0437\u0430? \u042f \u0436\u0435 \u0432\u043a\u043b\u044e\u0447\u0438\u043b!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0421\u043c\u043e\u0442\u0440\u044e \u043b\u043e\u0433\u0438. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0443\u0448\u043b\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u042f\u043d\u0434\u0435\u043a\u0441\u0430. \u0421\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0438\u043b 202 Accepted (\u0442\u043e \u0435\u0441\u0442\u044c \u201c\u043f\u0440\u0438\u043d\u044f\u043b, \u0441\u0435\u0439\u0447\u0430\u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c\u201d). \u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u044f \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e \u0441\u0442\u0430\u0442\u0443\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u042f\u043d\u0434\u0435\u043a\u0441 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0430\u0440\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u2014 \u201c\u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043e\u201d.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u0431\u043b\u0430\u043a\u0443 \u043d\u0443\u0436\u043d\u043e \u0432\u0440\u0435\u043c\u044f, \u0447\u0442\u043e\u0431\u044b:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1) \u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043d\u0430 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0440\u043e\u0437\u0435\u0442\u043a\u0443;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2) \u0420\u043e\u0437\u0435\u0442\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0449\u0435\u043b\u043a\u043d\u0443\u0442\u044c \u0440\u0435\u043b\u0435;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3) \u0420\u043e\u0437\u0435\u0442\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u0432 \u043e\u0431\u043b\u0430\u043a\u043e \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">4) \u041e\u0431\u043b\u0430\u043a\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u044d\u0448.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0410 \u044f \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e \u0441\u0442\u0430\u0442\u0443\u0441 \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043e\u0431\u043b\u0430\u043a\u043e \u0435\u0449\u0435 \u043d\u0435 \u0432 \u043a\u0443\u0440\u0441\u0435.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0420\u0435\u0448\u0435\u043d\u0438\u0435:&nbsp;<\/strong>Optimistic UI (\u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041d\u0435 \u0436\u0434\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0414\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1) \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0430\u043b \u201c\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u201d;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2) JavaScript \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0442\u0443\u043c\u0431\u043b\u0435\u0440 \u0432 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u201c\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u043e\u201d;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3) \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u0441\u0442 \u201c\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b\u2026\u201d;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">4) \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">5) \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0438\u043b 200\/202 \u2014 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u201c\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e\u201d \u0438 \u0441\u0442\u0430\u0432\u0438\u043c setTimeout \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 5 \u0441\u0435\u043a\u0443\u043d\u0434 (\u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u043b\u0430\u043a\u043e \u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u043d\u0435\u0442\u0441\u044f);<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">6) \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0435\u0440\u043d\u0443\u043b \u043e\u0448\u0438\u0431\u043a\u0443 \u2014 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e \u043e\u0442\u043a\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u0414\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u043a\u043b\u0438\u043a. \u041a\u0430\u043a \u0432 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u0410 \u201c\u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c\u201d \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u0438\u0442\u0440\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%D0%A7%D1%82%D0%BE_%D0%B2_%D0%B8%D1%82%D0%BE%D0%B3%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D0%BB%D0%BE%D1%81%D1%8C\"><\/span>\u0427\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1) \u0414\u0435\u043b\u0430\u0435\u0442 OAuth-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u042f\u043d\u0434\u0435\u043a\u0441\u0430<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2) \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439 \u0434\u0430\u0448\u0431\u043e\u0440\u0434 \u0441 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">3) \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 \u0440\u043e\u0437\u0435\u0442\u043a\u0438, \u043c\u0435\u043d\u044f\u0442\u044c \u044f\u0440\u043a\u043e\u0441\u0442\u044c \u043b\u0430\u043c\u043f, \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0443 \u043e\u0431\u043e\u0433\u0440\u0435\u0432\u0430\u0442\u0435\u043b\u0435\u0439<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">4) \u041a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0444\u0444\u043b\u0430\u0439\u043d-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u043a\u0440\u0438\u0432\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b API \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">5) \u041d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0438 Webpack, \u043d\u0438 Node.js, \u043d\u0438 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0412\u0441\u0451 \u044d\u0442\u043e \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c PHP + \u043d\u0435\u043c\u043d\u043e\u0433\u043e JavaScript + Tailwind CSS \u0447\u0435\u0440\u0435\u0437 CDN.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u041a\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u043e\u043a\u043e\u043b\u043e 400 \u0441\u0442\u0440\u043e\u043a. \u0414\u043b\u044f \u043a\u043e\u0433\u043e-\u0442\u043e \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e, \u0434\u043b\u044f \u043a\u043e\u0433\u043e-\u0442\u043e \u043c\u0430\u043b\u043e. \u041d\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0440\u0435\u0448\u0430\u0435\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u201c\u0434\u0435\u0440\u0433\u0430\u0435\u0442 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u201d.<\/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 - Null-Safe)\n * \u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 &quot;Cannot read properties of null&quot; \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 API\n *\/\nsession_start();\n\n\/\/ ==================== \u041d\u0410\u0421\u0422\u0420\u041e\u0419\u041a\u0418 ====================\n$CLIENT_ID     = &#039;sgsjhjdhj&#039;;\n$CLIENT_SECRET = &#039;tyjdtuksykdtuk&#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\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 ====================\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    session_write_close();\n    $iotHeaders = &#x5B;&quot;Authorization: Bearer {$token}&quot;];\n\n    if ($_GET&#x5B;&#039;api&#039;] === &#039;devices&#039;) {\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        $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        $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        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\/\/ ==================== \u0410\u0412\u0422\u041e\u0420\u0418\u0417\u0410\u0426\u0418\u042f ====================\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: &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&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.&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;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;\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            \/\/ === \u0418\u0421\u041f\u0420\u0410\u0412\u041b\u0415\u041d\u0418\u0415: \u0411\u0415\u0417\u041e\u041f\u0410\u0421\u041d\u041e\u0415 \u0418\u0417\u0412\u041b\u0415\u0427\u0415\u041d\u0418\u0415 \u0414\u0410\u041d\u041d\u042b\u0425 (Null-Safe) ===\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; \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            \/\/ === \u0418\u0421\u041f\u0420\u0410\u0412\u041b\u0415\u041d\u0418\u0415: \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 rangeCap?.state \u043f\u0435\u0440\u0435\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c ===\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        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;\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430&#039;);\n                    setTimeout(loadDevices, 5000);\n                } else {\n                    showToast((data.error || &#039;\u041e\u0448\u0438\u0431\u043a\u0430&#039;) + (data.details ? &#039;: &#039; + JSON.stringify(data.details) : &#039;&#039;), &#039;error&#039;);\n                    if (optimisticUpdate !== null) updateDeviceUI(deviceId, !optimisticUpdate);\n                }\n            } catch (e) {\n                showToast(&#039;\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<p class=\"wp-block-paragraph\">\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0430 \u043c\u043e\u0435\u043c \u0445\u043e\u043b\u043e\u0434\u0438\u043b\u044c\u043d\u0438\u043a\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/287\/5dd\/08e\/2875dd08eb4d2e1a8b46f85bfc6de4df.png\" alt=\"\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 PHP-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\" title=\"\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 PHP-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\"\/><figcaption class=\"wp-element-caption\">\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0443\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0430 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 PHP-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\u0418 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043b\u044e\u0431\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432\u043d\u0435 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0441\u0442\u0438 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u044f \u043c\u043e\u0433\u0443 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0430\u0440\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u0435\u043a \u043a\u043e\u0434\u0430. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442. \u0421\u0440\u0430\u0437\u0443 \u0441\u043a\u0430\u0436\u0443: \u044f \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043d\u043e \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u0435\u0449\u0435 \u0441 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0430 \u0443 \u043c\u0435\u043d\u044f \u0432\u044b\u043b\u0435\u0442\u0430\u043b\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0448\u0438\u0431\u043e\u043a, \u0447\u0442\u043e \u0438\u0445 \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u0438 \u043f\u043e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0443 \u0434\u0430\u0436\u0435 \u043e\u0434\u043d\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0437\u0430\u0441\u0438\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u043d\u0430 \u043e\u0434\u0438\u043d \u0432\u0435\u0447\u0435\u0440 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0433\u0443\u043b\u044f\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440. \u041f\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u044f \u0432\u043e\u043e\u0431\u0449\u0435 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u043b \u0434\u0430\u043b\u0435\u043a \u043e\u0442 IT. \u0418, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1107,"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":[368,370,372,369,284,371,253,37,367],"class_list":["post-1106","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-1","category-12","category-104","tag-esphome","tag-home-assistant","tag-php","tag-smart-home","tag-284","tag--php","tag-253","tag-37","tag-367"],"aioseo_notices":[],"tf_views":0,"tf_read_time":24,"_links":{"self":[{"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts\/1106","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=1106"}],"version-history":[{"count":1,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts\/1106\/revisions"}],"predecessor-version":[{"id":1108,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/posts\/1106\/revisions\/1108"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=\/wp\/v2\/media\/1107"}],"wp:attachment":[{"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/news.tfeya.ru\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}