{"id":317288,"date":"2021-02-01T15:00:41","date_gmt":"2021-02-01T15:00:41","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=317288"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=317288","title":{"rendered":"\u0414\u043e\u043c\u0430\u0448\u043d\u0435\u0435 IoT-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0433\u043b\u0430\u0437\u0430\u043c\u0438 JS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0412 \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u044b \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0435\u043c, \u0430 \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0435 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0435 IoT-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e? \u041d\u0435\u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044f, \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043d\u0435\u0437\u0432\u0430\u043d\u044b\u0445 \u0433\u043e\u0441\u0442\u0435\u0439 \u0438 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u044c \u0445\u043e\u0437\u044f\u0438\u043d\u0430. \u041a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u0447\u0442\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f?<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u043b\u043e \u044f\u0441\u043d\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u0434\u043e\u0439\u0442\u0438&nbsp;Raspberry pi \u0432 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u043a\u0430\u043c\u0435\u0440\u044b. \u041d\u0430 \u043d\u0435\u0433\u043e \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0434\u0440\u0430\u0439\u0432\u0435\u0440, \u043f\u043e\u0432\u0435\u0441\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0446\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u0430. \u0417\u0432\u0443\u0447\u0438\u0442 \u0432\u043f\u043e\u043b\u043d\u0435 \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0437\u0430\u043a\u0430\u0437\u0430\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>\u0441\u0430\u043c Raspberry<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0434\u0443\u043b\u044c \u043a\u0430\u043c\u0435\u0440\u044b<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0434\u0443\u043b\u044c \u0434\u0435\u0442\u0435\u043a\u0442\u043e\u0440\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0441 \u0418\u041a-\u043f\u0438\u0440\u043e\u044d\u043b\u0435\u043a\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u0430<\/p>\n<\/li>\n<\/ul>\n<p> \u0412 \u0437\u0430\u043a\u0430\u0437\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0431\u043b\u043e\u043a \u043f\u0438\u0442\u0430\u043d\u0438\u044f &#8212; \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u043c\u0435\u043d\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u0437\u0430\u0440\u044f\u0434\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043e\u0442 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 5V\/1A. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/943\/13e\/1e3\/94313e1e34038c65dfa33097cb519414.jpg\" width=\"1920\" height=\"1440\"><figcaption><\/figcaption><\/figure>\n<h2>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 IoT-\u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/h2>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433\u043e\u043c \u0431\u044b\u043b\u0430 \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430:<\/p>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/883\/b00\/d0d\/883b00d0d0f915f9282c8bd44604dab1.jpg\" alt=\"\" title=\"\" width=\"2214\" height=\"1022\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u044b\u043b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u0440\u0430\u0439\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043b \u0431\u044b \u0441\u0438\u0433\u043d\u0430\u043b \u0441 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b \u043a\u0430\u043c\u0435\u0440\u0443, \u0441\u043e\u0431\u0438\u0440\u0430\u043b \u0432\u0441\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b \u0434\u0430\u043b\u044c\u0448\u0435. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043d\u0430 Java \u0438 Python. <\/p>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u043b\u0430 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043a \u00ab\u0433\u0432\u043e\u0437\u0434\u044e\u00bb\u200e(\u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e \u043e\u0441\u043e\u0431\u043e\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u00ab\u0433\u0432\u043e\u0437\u0434\u0435\u00bb\u200e, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0440\u0430\u0444\u0438\u043a \u0441 \u043e\u0434\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b \u0431\u044b \u0431\u0430\u0437\u0443, \u043d\u043e \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0441\u0440\u0430\u0437\u0443 \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435). \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u00ab\u0433\u0432\u043e\u0437\u0434\u044f\u00bb\u200e &#8212; \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0440\u0430\u0444\u0438\u043a\u043e\u043c \u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0411\u0414 (\u043d\u0430 Postgres) \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u00ab\u0413\u0432\u043e\u0437\u0434\u044c\u00bb\u200e \u0431\u044b\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430 Java.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a \u0411\u0414 \u043e\u0431\u0440\u0430\u0449\u0430\u043b\u0438\u0441\u044c 3 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<ul>\n<li>\n<p>Rest API (Java) \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>Auth (Node.JS) &#8212; \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>Notification (Node.JS) &#8212; \u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f push-\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/p>\n<\/li>\n<\/ul>\n<p>\u0418, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0441\u0430\u043c\u043e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d React Native.<\/p>\n<p>\u041c\u044b \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u0441 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0435\u043c \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438: \u0442\u0430\u043a \u043a\u0430\u043a \u044f \u044f\u0432\u043b\u044f\u044e\u0441\u044c JS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c, \u044f \u0432\u0437\u044f\u043b \u043d\u0430 \u0441\u0435\u0431\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, Auth \u0438 Notification \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u044d\u0442\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0435 (\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e).<\/p>\n<h2>Auth service<\/h2>\n<p> \u0421\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/JSON_Web_Token\">JWT-\u0442\u043e\u043a\u0435\u043d\u0430<\/a>. \u041e\u043d \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>\u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>const router = require('express').Router(); const {loggedIn, adminOnly} = require(\"..\/helpers\/auth.middleware\"); const userController = require('..\/controllers\/user.controller');  \/\/ \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f router.post('\/register', userController.register);  \/\/ \u041b\u043e\u0433\u0438\u043d router.post('\/login', userController.login);  \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 router.get('\/auth', loggedIn, (req, res) =&gt; res.send(true));  \/\/ \u0422\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0430 router.get('\/adminonly', loggedIn, adminOnly, userController.adminonly);  module.exports = router;<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0445\u044d\u0448-\u043f\u0430\u0440\u043e\u043b\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/www.npmjs.com\/package\/bcryptjs\"><em>bcryptjs<\/em><\/a><em> <\/em>\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435 \u0432 \u0411\u0414.<\/p>\n<pre><code>exports.register = async (req, res) =&gt; {          \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0445\u044d\u0448     const salt = await bcrypt.genSalt(10);     const hasPassword = await bcrypt.hash(req.body.password, salt);      \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u044e\u0437\u0435\u0440\u0430      const user = new User({         mobile: req.body.mobile,         email: req.body.email,         username: req.body.username,         password: hasPassword,         status: req.body.status || 1     });     \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0411\u0414     try {         const id = await User.create(user);         user.id = id;         delete user.password;         res.send(user);     }     catch (err){         res.status(500).send({error: err.message});     } };<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0438\u043c\u0435\u0435\u043c \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e9a\/be0\/e0b\/e9abe0e0ba15ae34e3fc91bc0ef954c0.png\" width=\"986\" height=\"320\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u0441\u0430\u043c\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/jsonwebtoken\">jsonwebtoken<\/a>:<\/p>\n<pre><code>exports.login = async (req, res) =&gt; {     try {         \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c         const user = await User.login(req.body.username);         if (user) {             const validPass = await bcrypt.compare(req.body.password, user.password);             if (!validPass) return res.status(400).send({error: \"Password is wrong\"});              \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d             const token = jwt.sign({id: user.id, user_type_id: user.user_type_id}, config.TOKEN_SECRET,{ expiresIn: config.EXPIRATION});             res.header(\"auth-token\", token).send({\"token\": token, user: user.username});         }     }     catch (err) {         if( err instanceof NotFoundError ) {             res.status(401).send({error: err.message});         }         else {             const error_data = {                 entity: 'User',                 model_obj: {param: req.params, body: req.body},                 error_obj: err,                 error_msg: err.message             };             res.status(500).send(error_data);         }     }         };<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0431\u044b\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u043a\u0435\u043d\u0430:<\/p>\n<pre><code>exports.loggedIn = function (req, res, next) {     let token = req.header('Authorization');     if (!token) return res.status(401).send(\"Access Denied\");      try {     \t\/\/ \u0412\u044b\u0446\u0435\u043f\u043b\u044f\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430         if (token.startsWith('Bearer ')) {             token = token.slice(7, token.length).trimLeft();         }         \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c, \u0447\u0442\u043e \u0442\u043e\u043a\u0435\u043d \u0430\u043a\u0442\u0438\u0432\u0435\u043d         const verified = jwt.verify(token, config.TOKEN_SECRET);         req.user = verified;         next();     }     catch (err) {         res.status(400).send(\"Invalid Token\");     } }<\/code><\/pre>\n<h2>\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435:<\/p>\n<ol>\n<li>\n<p>\u044d\u043a\u0440\u0430\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u044d\u043a\u0440\u0430\u043d \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c, \u0443\u0434\u0430\u043b\u044f\u0442\u044c, \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e)<\/p>\n<\/li>\n<li>\n<p>\u044d\u043a\u0440\u0430\u043d \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439 (\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435\/\u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435)<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0438\u0437 \u043d\u0438\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0438\u0434\u0435\u043e<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0443 \u043c\u0435\u043d\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u0431\u044b\u043b\u043e \u043e\u043f\u044b\u0442\u0430 \u0432 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u0422\u0430\u043a \u043a\u0430\u043a \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c front-end \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u0445, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438 \u043d\u0430 React, \u0442\u043e \u0432\u044b\u0431\u043e\u0440 \u043f\u0430\u043b \u0441\u0440\u0430\u0437\u0443 \u043d\u0430 React Native.  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438 <a href=\"https:\/\/docs.expo.io\/\">Expo<\/a>. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u00ab\u200e\u0437\u0430\u00bb\u200e \u0438 \u00ab\u200e\u043f\u0440\u043e\u0442\u0438\u0432\u00bb\u200e:<\/p>\n<p><strong>\u041f\u043b\u044e\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Expo:<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u043e\u0441\u0442\u0430 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0437\u0430 \u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u043c\u0438\u043d\u0443\u0442\u044b;<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0449\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442 (\u0447\u0435\u0440\u0435\u0437 QR-\u043a\u043e\u0434 \u0438\u043b\u0438 \u0441\u0441\u044b\u043b\u043a\u0443) &#8212; \u0432\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0435\u0441\u044c \u0444\u0430\u0439\u043b .apk \u0438\u043b\u0438 .ipa;<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 (Push-\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f, Asset Manager,&#8230;).<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u041c\u0438\u043d\u0443\u0441\u044b:<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 Java \/ Objective-C;<\/p>\n<\/li>\n<li>\n<p>\u0418\u0437-\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0432\u0435\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u0437\u0432\u0435\u0441\u0438\u0432 \u0432\u0441\u0435 \u00ab\u200e\u0437\u0430\u00bb\u200e \u0438 \u00ab\u200e\u043f\u0440\u043e\u0442\u0438\u0432\u00bb, \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u0441 Expo \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0430\u043c\u044b\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442. \u0422\u0430\u043a \u043e\u043d\u043e \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u0438 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c. \u041d\u043e \u0435\u0441\u043b\u0438 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432\u044b, \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0432\u0441\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435 \u0442\u0430\u043a \u0440\u0430\u0434\u0443\u0436\u043d\u043e. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0434\u0435\u043b\u0430\u0442\u044c detach, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u043f\u043e \u043e\u043f\u044b\u0442\u0443 \u043c\u043d\u043e\u0433\u0438\u0445 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0445, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0440\u0438\u0432\u043e. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u043c\u043d\u0435 \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439 \u0445\u0432\u0430\u0442\u0438\u043b\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 Expo.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0432 \u043f\u0443\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u043e\u0442\u043a\u0440\u044b\u0432 \u0435\u0433\u043e, \u0441\u0440\u0430\u0437\u0443 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0439 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438 \u043d\u0430 React \u044f \u043d\u0435 \u0432\u0438\u0436\u0443. \u0410 \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u043e!<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 state-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u0432\u044b\u0431\u0440\u0430\u043b <a href=\"https:\/\/github.com\/mobxjs\/mobx-react\">MobX<\/a> &#8212; \u043c\u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f observable \u0438 \u0441 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<p>\u0414\u043b\u044f HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0441\u044c \u043a <a href=\"https:\/\/www.npmjs.com\/package\/axios\">axios<\/a>, \u043d\u043e \u0432 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/www.npmjs.com\/package\/superagent\">superagent<\/a> \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u044f. \u0412 \u0438\u0442\u043e\u0433\u0435, \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0431\u044b\u043b\u0438 \u0440\u0430\u0437\u0431\u0438\u0442\u044b \u043d\u0430 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>import superagentPromise from 'superagent-promise'; import _superagent from 'superagent'; import Auth from '.\/auth'; import Alarms from '.\/alarms'; import Notification from '.\/notification'; import Devices from '.\/devices'; import commonStore from \"..\/store\/commonStore\"; import authStore from \"..\/store\/authStore\"; import getEnvVars from \"..\/environment\";  const superagent = superagentPromise(_superagent, global.Promise);  const {apiRoot: API_ROOT} = getEnvVars();  const handleErrors = (err: any) =&gt; {     if (err &amp;&amp; err.response &amp;&amp; err.response.status === 401) {         authStore.logout();     }     return err; };  const responseBody = (res: any) =&gt; res.body;  \/\/\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043a \u0437\u0430\u043f\u0440\u043e\u0441\u0443 const tokenPlugin = (req: any) =&gt; {     if (commonStore.token) {         req.set('authorization', `Token ${commonStore.token}`);     } };  export interface RequestsAgent {     del: (url: string) =&gt; any;     get: (url: string) =&gt; any;     put: (url: string, body: object) =&gt; any;     post: (url: string, body: object, root?: string) =&gt; any; }  const requests: RequestsAgent = {     del: (url: string) =&gt;         superagent             .del(`${API_ROOT}${url}`)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody),     get: (url: string) =&gt;         superagent             .get(`${API_ROOT}${url}`)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody),     put: (url: string, body: object) =&gt;         superagent             .put(`${API_ROOT}${url}`, body)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody),     post: (url: string, body: object, root?: string) =&gt;         superagent             .post(`${root ? root : API_ROOT}${url}`, body)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody), };  export default {     Auth: Auth(requests),     Alarms: Alarms(requests),     Notification: Notification(requests),     Devices: Devices(requests) };<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 api \u0438\u0437 auth.ts:<\/p>\n<pre><code>import {RequestsAgent} from \".\/index\"; import getEnvVars from \"..\/environment\"; const {apiAuth} = getEnvVars();   export default (requests: RequestsAgent) =&gt; {     return {         login: (username: string, password: string) =&gt;             requests.post('\/api\/users\/login', {username, password}, apiAuth),         register: (username: string, email: string, password: string) =&gt;             requests.post('\/api\/users\/register', { user: { username, email, password } }),     }; }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a \u043d\u0438\u043c \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0438\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043c\u0435\u0441\u0442. \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 authStore:<\/p>\n<pre><code>    @action     register(): any {         this.inProgress = true;         this.errors = null;         return agent.Auth.register(this.values.username, this.values.email, this.values.password)             .then(({ user }) =&gt; commonStore.setToken(user.token))             .then(() =&gt; userStore.pullUser())             .catch(action((err) =&gt; {                 this.errors = err.response &amp;&amp; err.response.body &amp;&amp; err.response.body.errors;                 throw err;             }))             .finally(action(() =&gt; { this.inProgress = false; }));     }<\/code><\/pre>\n<p>\u041a \u0441\u043b\u043e\u0432\u0443 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 React Native, \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/Window\/localStorage\">LocalStorage<\/a>, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u0442\u044c <a href=\"https:\/\/reactnative.dev\/docs\/asyncstorage\">AsyncStorage<\/a>. \u0422\u0443\u0434\u0430 \u044f \u043f\u043e\u043b\u043e\u0436\u0438\u043b token \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 AsyncStorage \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435:<\/p>\n<pre><code>const token = await AsyncStorage.getItem('token');<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Expo \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441 BottomTabNavigator. \u041c\u043d\u0435 \u044d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u043e\u0448\u0435\u043b &#8212; \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0438 \u0434\u043b\u044f \u043d\u0443\u0436\u043d\u044b\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432:<\/p>\n<pre><code>const BottomTab = createBottomTabNavigator&lt;BottomTabParamList&gt;();  export default function BottomTabNavigator() {     const colorScheme = useColorScheme();      return (         &lt;BottomTab.Navigator             tabBarOptions={{activeTintColor: Colors[colorScheme].tint}}&gt;             &lt;BottomTab.Screen                 name=\"\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\"                 component={DeviceNavigator}                 options={{                     tabBarIcon: ({color}) =&gt; &lt;TabBarIcon name=\"calculator-outline\" color={color}&gt;&lt;\/TabBarIcon&gt;,                 }}             \/&gt;             &lt;BottomTab.Screen                 name=\"\u0421\u043e\u0431\u044b\u0442\u0438\u044f\"                 component={AlarmsNavigator}                 options={{                     tabBarIcon: ({color}) =&gt; &lt;NotificationBadge color={color}\/&gt;,                 }}             \/&gt;         &lt;\/BottomTab.Navigator&gt;     ); }<\/code><\/pre>\n<p>\u0418 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 &#8212; \u0441\u0430\u043c DeviceNavigator:<\/p>\n<pre><code>const TabThreeStack = createStackNavigator&lt;TabThreeParamList&gt;();  function DeviceNavigator() {     const navigation = useNavigation();     const {colors} = useTheme();     return (         &lt;TabThreeStack.Navigator&gt;             &lt;TabThreeStack.Screen                 name=\"DeviceScreen\"                 component={DevicesScreen}                 options={{                     headerTitle: '\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430',                     headerRight: () =&gt; &lt;Ionicons color={colors.primary} onPress={() =&gt; navigation.navigate('DeviceScreenAdd')} name={\"add-circle-outline\"}\/&gt;                 }}             \/&gt;             &lt;TabThreeStack.Screen                 name=\"AddDeviceScreen\"                 component={AddDeviceScreen}                 options={{                     headerTitle: '\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e'                 }}             \/&gt;             &lt;TabThreeStack.Screen                 name=\"DeviceInfoScreen\"                 component={DeviceInfoScreen}                 options={{                     headerTitle: '\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435'                 }}             \/&gt;         &lt;\/TabThreeStack.Navigator&gt;     ); }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0430\u043c\u0438\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0438 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0434\u043b\u044f react-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e \u0441\u0432\u043e\u0438\u043c\u0438 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u044f\u043c\u0438. \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0442\u0430\u043a\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u044b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/638\/219\/bd7\/638219bd7a40487e8ec54c1e3840a03b.png\" width=\"2000\" height=\"1792\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/expo-video-player\">expo-video-player<\/a>. \u0412\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0441\u0430\u043c \u0432\u0438\u0434\u0435\u043e\u043f\u043b\u0435\u0435\u0440, \u0432 uri \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u0442\u0440\u0438\u043c \u0432\u0438\u0434\u0435\u043e. \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0431\u044b\u043b\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Range\">Content-range<\/a>. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3e3\/412\/921\/3e341292199db22f0226e872274cd8a1.png\" width=\"320\" height=\"693\"><figcaption><\/figcaption><\/figure>\n<h2>Notification service<\/h2>\n<p>\u0414\u043b\u044f push-\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u041d\u0430\u0448\u0438 push \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 \u0411\u0414. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0435\u0448\u0430\u0435\u043c \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c:<\/p>\n<pre><code>    client.query('LISTEN new_alarm_event');      client.on('notification', async (data) =&gt; {         writeToAll(data.payload)     });<\/code><\/pre>\n<p>\u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0433\u043e\u0432\u043e\u0440\u0438\u043c expo \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u044e:<\/p>\n<pre><code>const writeToAll = async msg =&gt; {     const tokensArray = Array.from(tokensSet);      if (tokensArray.length &gt; 0) {         const messages = tokensArray.map(token =&gt; ({             to: token,             sound: 'default',             body: msg,             data: { msg },         })) \t\t\t\t\/\/ \u0413\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u0440\u0430\u0437\u043e\u043c         let chunks = expo.chunkPushNotifications(messages);          (async () =&gt; {             for (let chunk of chunks) {                 try {                 \t\t\/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u043a\u0435\u0442 \u0432 \u0441\u043b\u0443\u0436\u0431\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 Expo                     const receipts = await expo.sendPushNotificationsAsync(chunk);                     console.log(receipts);                 } catch (error) {                     console.error(error);                 }             }         })();     }     else {         console.log(`cant write, ${tokensArray.length} users`)     }      return tokensArray.length }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0432 \u0441\u0430\u043c\u043e\u043c \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438:<\/p>\n<pre><code> const registerForPushNotifications = async () =&gt; {     const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);     if (status !== 'granted') {         alert('No notification permissions!');         return;     } \t\t\/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430     let token = await Notifications.getExpoPushTokenAsync(); \t\t\/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u0432 \u043d\u0430\u0448 notification service     await sendPushNotification(token); }  export default registerForPushNotifications;<\/code><\/pre>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u044b\u043b\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 IoT-\u0441\u0438\u0441\u0442\u0435\u043c\u0430. \u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439  \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u0430\u0434\u0430\u0447\u0435\u0439. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0445 \u043f\u043b\u0430\u043d\u0430\u0445 &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0445\u043e\u0437\u044f\u0438\u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0434\u0435\u0442\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u0445\u043e\u0434\u0430 (\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 \u0445\u043e\u0437\u044f\u0438\u043d\u0430). <\/p>\n<p>\u041e\u0446\u0435\u043d\u0438\u0432\u0430\u044f \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043d\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443, \u043c\u043d\u0435 \u043f\u0440\u0438\u044f\u0442\u043d\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0432 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u043d\u0430\u043d\u0438\u0435 JS \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e frontend \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439, \u043d\u043e \u0438 \u0431\u0440\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0431\u044f \u0437\u0430\u0434\u0430\u0447\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 backend, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0438 \u0434\u0435\u0441\u043a\u0442\u043e\u043f\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439. \u042d\u0442\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u043a\u0440\u0443\u0433\u043e\u0437\u043e\u0440 \u0438 \u0434\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0432\u0441\u0435.<\/p>\n<p>\u0412\u0441\u0435\u043c \u0434\u043e\u0431\u0440\u0430!<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/megafon\/blog\/540334\/\"> https:\/\/habr.com\/ru\/company\/megafon\/blog\/540334\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0412 \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u044b \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0438\u0441\u044c \u0441 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0435\u043c, \u0430 \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0435 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0435 IoT-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e? \u041d\u0435\u0434\u043e\u043b\u0433\u043e \u0434\u0443\u043c\u0430\u044f, \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043d\u0435\u0437\u0432\u0430\u043d\u044b\u0445 \u0433\u043e\u0441\u0442\u0435\u0439 \u0438 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u044c \u0445\u043e\u0437\u044f\u0438\u043d\u0430. \u041a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u0447\u0442\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f?<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u043b\u043e \u044f\u0441\u043d\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u0434\u043e\u0439\u0442\u0438&nbsp;Raspberry pi \u0432 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u043a\u0430\u043c\u0435\u0440\u044b. \u041d\u0430 \u043d\u0435\u0433\u043e \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0434\u0440\u0430\u0439\u0432\u0435\u0440, \u043f\u043e\u0432\u0435\u0441\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0446\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u0430. \u0417\u0432\u0443\u0447\u0438\u0442 \u0432\u043f\u043e\u043b\u043d\u0435 \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0437\u0430\u043a\u0430\u0437\u0430\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>\u0441\u0430\u043c Raspberry<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0434\u0443\u043b\u044c \u043a\u0430\u043c\u0435\u0440\u044b<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0434\u0443\u043b\u044c \u0434\u0435\u0442\u0435\u043a\u0442\u043e\u0440\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0441 \u0418\u041a-\u043f\u0438\u0440\u043e\u044d\u043b\u0435\u043a\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u0430<\/p>\n<\/li>\n<\/ul>\n<p> \u0412 \u0437\u0430\u043a\u0430\u0437\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0431\u043b\u043e\u043a \u043f\u0438\u0442\u0430\u043d\u0438\u044f &#8212; \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u043c\u0435\u043d\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u0437\u0430\u0440\u044f\u0434\u043d\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043e\u0442 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 5V\/1A. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h2>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 IoT-\u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/h2>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433\u043e\u043c \u0431\u044b\u043b\u0430 \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430:<\/p>\n<figure class=\"bordered full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u044b\u043b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u0440\u0430\u0439\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043b \u0431\u044b \u0441\u0438\u0433\u043d\u0430\u043b \u0441 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b \u043a\u0430\u043c\u0435\u0440\u0443, \u0441\u043e\u0431\u0438\u0440\u0430\u043b \u0432\u0441\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b \u0434\u0430\u043b\u044c\u0448\u0435. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043d\u0430 Java \u0438 Python. <\/p>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u043b\u0430 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043a \u00ab\u0433\u0432\u043e\u0437\u0434\u044e\u00bb\u200e(\u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043d\u0435 \u0431\u044b\u043b\u043e \u043e\u0441\u043e\u0431\u043e\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u00ab\u0433\u0432\u043e\u0437\u0434\u0435\u00bb\u200e, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0440\u0430\u0444\u0438\u043a \u0441 \u043e\u0434\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b \u0431\u044b \u0431\u0430\u0437\u0443, \u043d\u043e \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0441\u0440\u0430\u0437\u0443 \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435). \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u00ab\u0433\u0432\u043e\u0437\u0434\u044f\u00bb\u200e &#8212; \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0440\u0430\u0444\u0438\u043a\u043e\u043c \u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0411\u0414 (\u043d\u0430 Postgres) \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u00ab\u0413\u0432\u043e\u0437\u0434\u044c\u00bb\u200e \u0431\u044b\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430 Java.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a \u0411\u0414 \u043e\u0431\u0440\u0430\u0449\u0430\u043b\u0438\u0441\u044c 3 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<ul>\n<li>\n<p>Rest API (Java) \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>Auth (Node.JS) &#8212; \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>Notification (Node.JS) &#8212; \u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f push-\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/p>\n<\/li>\n<\/ul>\n<p>\u0418, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0441\u0430\u043c\u043e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d React Native.<\/p>\n<p>\u041c\u044b \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u0441 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0435\u043c \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438: \u0442\u0430\u043a \u043a\u0430\u043a \u044f \u044f\u0432\u043b\u044f\u044e\u0441\u044c JS-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c, \u044f \u0432\u0437\u044f\u043b \u043d\u0430 \u0441\u0435\u0431\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, Auth \u0438 Notification \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u044d\u0442\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0435 (\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e).<\/p>\n<h2>Auth service<\/h2>\n<p> \u0421\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/JSON_Web_Token\">JWT-\u0442\u043e\u043a\u0435\u043d\u0430<\/a>. \u041e\u043d \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>\u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>const router = require('express').Router(); const {loggedIn, adminOnly} = require(\"..\/helpers\/auth.middleware\"); const userController = require('..\/controllers\/user.controller');  \/\/ \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f router.post('\/register', userController.register);  \/\/ \u041b\u043e\u0433\u0438\u043d router.post('\/login', userController.login);  \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 router.get('\/auth', loggedIn, (req, res) =&gt; res.send(true));  \/\/ \u0422\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0430 router.get('\/adminonly', loggedIn, adminOnly, userController.adminonly);  module.exports = router;<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0445\u044d\u0448-\u043f\u0430\u0440\u043e\u043b\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/www.npmjs.com\/package\/bcryptjs\"><em>bcryptjs<\/em><\/a><em> <\/em>\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435 \u0432 \u0411\u0414.<\/p>\n<pre><code>exports.register = async (req, res) =&gt; {          \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0445\u044d\u0448     const salt = await bcrypt.genSalt(10);     const hasPassword = await bcrypt.hash(req.body.password, salt);      \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u044e\u0437\u0435\u0440\u0430      const user = new User({         mobile: req.body.mobile,         email: req.body.email,         username: req.body.username,         password: hasPassword,         status: req.body.status || 1     });     \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0411\u0414     try {         const id = await User.create(user);         user.id = id;         delete user.password;         res.send(user);     }     catch (err){         res.status(500).send({error: err.message});     } };<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0438\u043c\u0435\u0435\u043c \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u0441\u0430\u043c\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/jsonwebtoken\">jsonwebtoken<\/a>:<\/p>\n<pre><code>exports.login = async (req, res) =&gt; {     try {         \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c         const user = await User.login(req.body.username);         if (user) {             const validPass = await bcrypt.compare(req.body.password, user.password);             if (!validPass) return res.status(400).send({error: \"Password is wrong\"});              \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0442\u043e\u043a\u0435\u043d             const token = jwt.sign({id: user.id, user_type_id: user.user_type_id}, config.TOKEN_SECRET,{ expiresIn: config.EXPIRATION});             res.header(\"auth-token\", token).send({\"token\": token, user: user.username});         }     }     catch (err) {         if( err instanceof NotFoundError ) {             res.status(401).send({error: err.message});         }         else {             const error_data = {                 entity: 'User',                 model_obj: {param: req.params, body: req.body},                 error_obj: err,                 error_msg: err.message             };             res.status(500).send(error_data);         }     }         };<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0431\u044b\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u043a\u0435\u043d\u0430:<\/p>\n<pre><code>exports.loggedIn = function (req, res, next) {     let token = req.header('Authorization');     if (!token) return res.status(401).send(\"Access Denied\");      try {     \t\/\/ \u0412\u044b\u0446\u0435\u043f\u043b\u044f\u0435\u043c \u0442\u043e\u043a\u0435\u043d \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430         if (token.startsWith('Bearer ')) {             token = token.slice(7, token.length).trimLeft();         }         \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c, \u0447\u0442\u043e \u0442\u043e\u043a\u0435\u043d \u0430\u043a\u0442\u0438\u0432\u0435\u043d         const verified = jwt.verify(token, config.TOKEN_SECRET);         req.user = verified;         next();     }     catch (err) {         res.status(400).send(\"Invalid Token\");     } }<\/code><\/pre>\n<h2>\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435:<\/p>\n<ol>\n<li>\n<p>\u044d\u043a\u0440\u0430\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u044d\u043a\u0440\u0430\u043d \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c, \u0443\u0434\u0430\u043b\u044f\u0442\u044c, \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e)<\/p>\n<\/li>\n<li>\n<p>\u044d\u043a\u0440\u0430\u043d \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439 (\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435\/\u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435)<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0438\u0437 \u043d\u0438\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0438\u0434\u0435\u043e<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0443 \u043c\u0435\u043d\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u0431\u044b\u043b\u043e \u043e\u043f\u044b\u0442\u0430 \u0432 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u0422\u0430\u043a \u043a\u0430\u043a \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c front-end \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u0445, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438 \u043d\u0430 React, \u0442\u043e \u0432\u044b\u0431\u043e\u0440 \u043f\u0430\u043b \u0441\u0440\u0430\u0437\u0443 \u043d\u0430 React Native.  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438 <a href=\"https:\/\/docs.expo.io\/\">Expo<\/a>. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u00ab\u200e\u0437\u0430\u00bb\u200e \u0438 \u00ab\u200e\u043f\u0440\u043e\u0442\u0438\u0432\u00bb\u200e:<\/p>\n<p><strong>\u041f\u043b\u044e\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Expo:<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u043e\u0441\u0442\u0430 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0437\u0430 \u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u043c\u0438\u043d\u0443\u0442\u044b;<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0449\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442 (\u0447\u0435\u0440\u0435\u0437 QR-\u043a\u043e\u0434 \u0438\u043b\u0438 \u0441\u0441\u044b\u043b\u043a\u0443) &#8212; \u0432\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0435\u0441\u044c \u0444\u0430\u0439\u043b .apk \u0438\u043b\u0438 .ipa;<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 (Push-\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f, Asset Manager,&#8230;).<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u041c\u0438\u043d\u0443\u0441\u044b:<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 Java \/ Objective-C;<\/p>\n<\/li>\n<li>\n<p>\u0418\u0437-\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0432\u0435\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u0437\u0432\u0435\u0441\u0438\u0432 \u0432\u0441\u0435 \u00ab\u200e\u0437\u0430\u00bb\u200e \u0438 \u00ab\u200e\u043f\u0440\u043e\u0442\u0438\u0432\u00bb, \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u0441 Expo \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0430\u043c\u044b\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442. \u0422\u0430\u043a \u043e\u043d\u043e \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u0438 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c. \u041d\u043e \u0435\u0441\u043b\u0438 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432\u044b, \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0432\u0441\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435 \u0442\u0430\u043a \u0440\u0430\u0434\u0443\u0436\u043d\u043e. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0434\u0435\u043b\u0430\u0442\u044c detach, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u043f\u043e \u043e\u043f\u044b\u0442\u0443 \u043c\u043d\u043e\u0433\u0438\u0445 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0445, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0440\u0438\u0432\u043e. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u043c\u043d\u0435 \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439 \u0445\u0432\u0430\u0442\u0438\u043b\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 Expo.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0432 \u043f\u0443\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u043e\u0442\u043a\u0440\u044b\u0432 \u0435\u0433\u043e, \u0441\u0440\u0430\u0437\u0443 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0439 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438 \u043d\u0430 React \u044f \u043d\u0435 \u0432\u0438\u0436\u0443. \u0410 \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u043e!<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 state-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u0432\u044b\u0431\u0440\u0430\u043b <a href=\"https:\/\/github.com\/mobxjs\/mobx-react\">MobX<\/a> &#8212; \u043c\u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f observable \u0438 \u0441 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<p>\u0414\u043b\u044f HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0441\u044c \u043a <a href=\"https:\/\/www.npmjs.com\/package\/axios\">axios<\/a>, \u043d\u043e \u0432 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/www.npmjs.com\/package\/superagent\">superagent<\/a> \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u044f. \u0412 \u0438\u0442\u043e\u0433\u0435, \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0431\u044b\u043b\u0438 \u0440\u0430\u0437\u0431\u0438\u0442\u044b \u043d\u0430 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>import superagentPromise from 'superagent-promise'; import _superagent from 'superagent'; import Auth from '.\/auth'; import Alarms from '.\/alarms'; import Notification from '.\/notification'; import Devices from '.\/devices'; import commonStore from \"..\/store\/commonStore\"; import authStore from \"..\/store\/authStore\"; import getEnvVars from \"..\/environment\";  const superagent = superagentPromise(_superagent, global.Promise);  const {apiRoot: API_ROOT} = getEnvVars();  const handleErrors = (err: any) =&gt; {     if (err &amp;&amp; err.response &amp;&amp; err.response.status === 401) {         authStore.logout();     }     return err; };  const responseBody = (res: any) =&gt; res.body;  \/\/\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043a \u0437\u0430\u043f\u0440\u043e\u0441\u0443 const tokenPlugin = (req: any) =&gt; {     if (commonStore.token) {         req.set('authorization', `Token ${commonStore.token}`);     } };  export interface RequestsAgent {     del: (url: string) =&gt; any;     get: (url: string) =&gt; any;     put: (url: string, body: object) =&gt; any;     post: (url: string, body: object, root?: string) =&gt; any; }  const requests: RequestsAgent = {     del: (url: string) =&gt;         superagent             .del(`${API_ROOT}${url}`)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody),     get: (url: string) =&gt;         superagent             .get(`${API_ROOT}${url}`)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody),     put: (url: string, body: object) =&gt;         superagent             .put(`${API_ROOT}${url}`, body)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody),     post: (url: string, body: object, root?: string) =&gt;         superagent             .post(`${root ? root : API_ROOT}${url}`, body)             .use(tokenPlugin)             .end(handleErrors)             .then(responseBody), };  export default {     Auth: Auth(requests),     Alarms: Alarms(requests),     Notification: Notification(requests),     Devices: Devices(requests) };<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 api \u0438\u0437 auth.ts:<\/p>\n<pre><code>import {RequestsAgent} from \".\/index\"; import getEnvVars from \"..\/environment\"; const {apiAuth} = getEnvVars();   export default (requests: RequestsAgent) =&gt; {     return {         login: (username: string, password: string) =&gt;             requests.post('\/api\/users\/login', {username, password}, apiAuth),         register: (username: string, email: string, password: string) =&gt;             requests.post('\/api\/users\/register', { user: { username, email, password } }),     }; }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a \u043d\u0438\u043c \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0438\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043c\u0435\u0441\u0442. \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 authStore:<\/p>\n<pre><code>    @action     register(): any {         this.inProgress =<\/code><\/pre>\n<\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-317288","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/317288","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=317288"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/317288\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=317288"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=317288"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=317288"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}