{"id":454050,"date":"2025-04-01T15:48:27","date_gmt":"2025-04-01T15:48:27","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=454050"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=454050","title":{"rendered":"<span>\u0414\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e MTC Exolve \u0438 GSM \u043c\u043e\u0434\u0443\u043b\u044f<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a, \u043f\u0440\u043e\u043a\u043b\u044f\u0442\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0444\u0440\u0430\u0437\u044b\u00a0 \u00ab\u0442\u044b\u0436 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u2026\u00bb, \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u0440\u0435\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438 \u043c\u0435\u043d\u044f. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u0441\u043f\u0440\u043e\u0441\u0438\u043b\u0438 \u0441\u043e\u0432\u0435\u0442\u0430, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u044f \u043d\u0443\u0436\u043d\u044b\u0445 \u043b\u044e\u0434\u0435\u0439 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b\u0441\u044f \u0431\u0435\u0437 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u043d\u0434\u0435\u0440\u0430 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.\u00a0<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u0445\u043e\u0434\u0443 \u044f \u043d\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441, \u043d\u043e \u0437\u0430\u0434\u0430\u0447\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u043e\u0439, \u0438 \u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u0443\u0447\u0438\u043b \u0432\u043e\u043f\u0440\u043e\u0441.\u00a0<\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u0451\u043b \u0431\u044b\u0441\u0442\u0440\u043e \u2014 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c GSM-\u0440\u0435\u043b\u0435, \u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0438\u043a\u0440\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<p>\u0418 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043c\u0435\u043d\u044f \u043d\u0430\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a <a href=\"https:\/\/exolve.ru\/products\/voice-api\/?utm_source=habr&amp;utm_medium=refferal&amp;utm_campaign=voiceapi_article&amp;utm_content=article_remotecontrol&amp;utm_term=voiceapi_exolve\">\u041c\u0422\u0421 Exolve<\/a>, \u0433\u0440\u0435\u0445 \u0431\u044b\u043b\u043e \u0438\u043c \u043d\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u0422\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 <a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=106332469\">API \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c<\/a> \u0435\u0441\u0442\u044c.<\/p>\n<p><strong>\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"#a1\">\u0427\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a2\">\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a3\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0423\u0412\u0412 API \u041c\u0422\u0421 Exolve<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a4\">\u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a5\">\u0418\u0442\u043e\u0433\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a6\">\u0411\u043e\u043d\u0443\u0441 \u2013 CRUD API<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0435\u0441\u0442\u043d\u043e, \u044f \u043d\u0435 \u0437\u043d\u0430\u0442\u043e\u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043b\u044e\u0431\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0438\u043a \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u00abGSM \u043c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u00bb.\u00a0 \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0443 \u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432 \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0438 (\u0440\u0430\u0437\u043c\u044b\u043a\u0430\u043d\u0438\u0438 \u0440\u0435\u043b\u0435) \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0442\u044c \u0438 \u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c.<\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435, \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u043c\u043e\u0436\u043d\u043e \u0438 \u043d\u0435 \u0433\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0437\u0434\u0430\u0442\u044c \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 SIM-\u043a\u0430\u0440\u0442\u044b \u0432 GSM-\u043c\u043e\u0434\u0443\u043b\u0435. \u041d\u043e \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u043d\u043e\u043c\u0435\u0440 \u0441\u0442\u0430\u043d\u0435\u0442 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0442\u0440\u0435\u0442\u044c\u0438\u043c \u043b\u0438\u0446\u0430\u043c? \u041d\u0430\u043c \u044f\u0432\u043d\u043e \u043d\u0443\u0436\u0435\u043d \u0431\u0435\u043b\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043d\u044b\u0445 \u043d\u043e\u043c\u0435\u0440\u043e\u0432. \u041f\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0440\u0435\u0448\u0430\u044e\u0442 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438. \u041d\u043e \u043c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0432 \u0440\u0443\u043a\u0430\u0445 FastAPI. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044e \u0437\u0432\u043e\u043d\u044f\u0449\u0438\u0445 \u0441 \u00ab\u043a\u0430\u0440\u0442\u043e\u0448\u043d\u044b\u043c\u0438 \u0438\u0433\u0440\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u0447\u0438\u043c\u0438 \u0443\u0432\u0435\u0441\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438\u00bb.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0434\u0435\u043b\u0443 \u2013 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0434\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440. \u042f \u043d\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442.\u00a0 \u0417\u0430\u0434\u0430\u0447\u0443 \u044f \u0440\u0435\u0448\u0430\u043b \u0441\u043a\u043e\u0440\u0435\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0438 \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u044b \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u043f\u0440\u043e\u0434\u0443\u043c\u044b\u0432\u0430\u043b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043d\u0430\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043a \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c \u0441\u0442\u0430\u0442\u044c\u0438, \u043a\u0430\u043a \u043a \u0438\u0441\u0442\u0438\u043d\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u043e\u0439 \u0441\u0440\u0435\u0434\u0435.<\/p>\n<p><a class=\"anchor\" name=\"a1\" id=\"a1\"><\/a><\/p>\n<h2>\u0427\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/h2>\n<p>\u0424\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0443\u043b\u0430\u0436\u0435\u043d\u044b \u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u0434\u0435\u043b\u0443.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439:<\/p>\n<p><strong>\u041f\u0440\u0435\u0434\u0443\u0441\u043b\u043e\u0432\u0438\u044f.<\/strong><\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e (\u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0434\u0432\u0435) \u0437\u043e\u043d\u044b, \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0435 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u043c\u0438, \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u043e\u0438\u0442 \u0441\u0432\u043e\u0439 GSM-\u043c\u043e\u0434\u0443\u043b\u044c.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0434\u043d\u043e\u0439 \u0438\u043b\u0438 \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u0437\u043e\u043d\u0430\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u0434\u044a\u0435\u0437\u0436\u0430\u0435\u0442 \u043a \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0431\u0438\u0440\u0430\u0435\u0442 \u043d\u043e\u043c\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p>MT\u0421 Exolve \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043d\u0430\u043c \u0432 \u0441\u0435\u0440\u0432\u0438\u0441<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0432 \u043a\u0430\u043a\u0438\u0435 \u0437\u043e\u043d\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u043f\u0440\u043e\u0435\u0437\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0431\u0437\u0432\u043e\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0428\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u044b \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<p><\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6d7\/a59\/2cb\/6d7a592cb4a0d4024ecff49d555e4195.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u043c\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u043c\" width=\"501\" height=\"783\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6d7\/a59\/2cb\/6d7a592cb4a0d4024ecff49d555e4195.png\"\/><\/p>\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u043c<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"#a2\" id=\"#a2\"><\/a><\/p>\n<h2>\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438\u0437 \u0431\u0435\u043b\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0430 \u044f \u0432\u0437\u044f\u043b SQlite \u0438\u0431\u043e \u0435\u0451 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0430\u043c \u0445\u0432\u0430\u0442\u0438\u0442 \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439, \u0430 \u0435\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u00ab\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u00bb \u0432 Python 3.<\/p>\n<p>\u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u0432\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b:<\/p>\n<ul>\n<li>\n<p>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0432\u043e\u043d\u0438\u0442\u044c \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u044b\u0439 \u043d\u043e\u043c\u0435\u0440 (users).\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043d\u043e\u043c\u0435\u0440\u0430\u0445 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430\u0445 GSM-\u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0432 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u0445 \u0438 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u043c\u044b\u0445 \u0438\u043c\u0438 \u0437\u043e\u043d\u0430\u0445 (barriers).<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0432\u044f\u0437\u0438 \u043c\u043d\u043e\u0433\u0438\u0435-\u043a\u043e-\u043c\u043d\u043e\u0433\u0438\u043c, \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0440\u0435\u0442\u044c\u044e \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0443 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0438\u043c \u0437\u043e\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u0437\u0434\u0430 (users_access).<\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f87\/acf\/5dd\/f87acf5dd83e231c67e329b6da780918.png\" alt=\"ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430\" title=\"ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430\" width=\"1215\" height=\"399\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f87\/acf\/5dd\/f87acf5dd83e231c67e329b6da780918.png\"\/><\/p>\n<div><figcaption>ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e64\/b7d\/52b\/e64b7d52b4280099aa3eb11e1468432b.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0411\u0414\" title=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0411\u0414\" width=\"762\" height=\"326\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e64\/b7d\/52b\/e64b7d52b4280099aa3eb11e1468432b.png\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0411\u0414<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u044f \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043b \u043d\u0430 <a href=\"https:\/\/github.com\/bosonbeard\/mts-habr\/tree\/main\/barrier_control\"><strong>GitHub<\/strong><\/a><strong>, <\/strong>\u0432\u043e\u0437\u0434\u0435\u0440\u0436\u0443\u0441\u044c \u043e\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0442\u0430\u0431\u043b\u0438\u0446..<\/p>\n<p>\u041e\u0442\u043c\u0435\u0447\u0443 \u0442\u043e\u043b\u044c\u043a\u043e, \u0447\u0442\u043e \u0432 user_access \u0441\u043e\u0441\u0442\u0430\u0432\u043d\u043e\u0439 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u043e\u0431\u043e\u0438\u0445 \u043f\u043e\u043b\u0435\u0439, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0431\u0430 \u043f\u043e\u043b\u044f \u044d\u0442\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445.\u00a0<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0430 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430.<\/p>\n<p>\u041e\u0434\u0438\u043d \u0434\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0433\u043e\u0441\u0442\u0435\u0439 (#1), \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 (\u21162) \u0434\u043b\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ce1\/b43\/f5f\/ce1b43f5f9224676dd19ca6c83b694c2.png\" alt=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b barriers\" title=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b barriers\" width=\"344\" height=\"155\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ce1\/b43\/f5f\/ce1b43f5f9224676dd19ca6c83b694c2.png\"\/><\/p>\n<div><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b barriers<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u0441\u0435 \u0438\u043c\u0435\u043d\u0430 \u0438 \u043d\u043e\u043c\u0435\u0440\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u0432 \u0432\u044b\u0434\u0443\u043c\u0430\u043d\u044b, \u043b\u044e\u0431\u044b\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b.\u00a0<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>\u041e\u0434\u043d\u043e\u0433\u043e \u0433\u043e\u0441\u0442\u044f (Habr) \u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430 (Habra).<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/070\/816\/042\/070816042994867423e788be647b62ed.png\" alt=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users\" title=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users\" width=\"502\" height=\"149\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/070\/816\/042\/070816042994867423e788be647b62ed.png\"\/><\/p>\n<div><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0434\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u044b. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c Habr \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0435\u0445\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c, \u0430 Habra \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0435\u0445\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0430.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/152\/306\/c9a\/152306c9afd7509db40dfb40f8887577.png\" alt=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users_access\" title=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users_access\" width=\"220\" height=\"168\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/152\/306\/c9a\/152306c9afd7509db40dfb40f8887577.png\"\/><\/p>\n<div><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users_access<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"a3\" id=\"a3\"><\/a><\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0423\u0412\u0412 API \u041c\u0422\u0421 Exolve<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0432 <a href=\"https:\/\/exolve.ru\/products\/voice-api\/?utm_source=habr&amp;utm_medium=refferal&amp;utm_campaign=voiceapi_article&amp;utm_content=article_remotecontrol&amp;utm_term=voiceapi_exolve\">\u041c\u0422\u0421 Exolve<\/a>. \u042f \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043a \u043d\u0435\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f.<\/p>\n<p><a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=108497488\">\u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>setSipCallControlU<\/code> \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c URL, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 Exolve \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0437\u0430 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441:<\/p>\n<p><a href=\"https:\/\/api.mtt.ru\/ipcr\/\">https:\/\/api.mtt.ru\/ipcr\/<\/a> (\u0443\u043a\u0430\u0437\u0430\u0432 \u0432 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c).<\/p>\n<p>\u0422\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<pre><code class=\"json\">{ \u00a0\u00a0\u00a0\u00a0\"id\":\"1\", \u00a0\u00a0\u00a0\u00a0\"jsonrpc\":\"2.0\", \u00a0\u00a0\u00a0\u00a0\"method\": \"setSipCallControlURL\", \u00a0\u00a0\u00a0\u00a0\"params\": { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"sip_id\": \"\u0412\u0430\u0448 SIP ID (\u043d\u043e\u043c\", \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"url\": \"\u0412\u0430\u0448 URL\" \u00a0\u00a0\u00a0\u00a0} }<\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435\u00a0 <code>sip_id<\/code> \u2013 \u044d\u0442\u043e \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0443\u0442 \u0437\u0432\u043e\u043d\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438. \u0410 <code>url<\/code> \u2013 \u044d\u0442\u043e \u0430\u0434\u0440\u0435\u0441 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043a\u0430\u0436\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0430 &lt;\u0432\u0430\u0448 \u0434\u043e\u043c\u0435\u043d \u0438\u043b\u0438 IP&gt;\/access.<\/p>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0443<a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=108497490\">\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0439 \u043d\u043e\u043c\u0435\u0440<\/a>, \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439 \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u043e\u043c\u0435\u0440 \u043f\u043e\u0441\u0442\u0430 \u043e\u0445\u0440\u0430\u043d\u044b.<\/p>\n<p><a class=\"anchor\" name=\"a4\" id=\"a4\"><\/a><\/p>\n<h2>\u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0437\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b Python v. 3.10 \u0438 fastapi v. 0.115, \u043d\u043e \u0434\u0443\u043c\u0430\u044e, \u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0443\u0442 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<p>\u041e\u0441\u0432\u0435\u0436\u0438\u043c \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, \u0441\u0445\u0435\u043c\u0443 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0451 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/02b\/4b1\/71a\/02b4b171ae89085e9ed1157e843e441a.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Exolve\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Exolve\" width=\"1600\" height=\"752\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/02b\/4b1\/71a\/02b4b171ae89085e9ed1157e843e441a.png\"\/><\/p>\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Exolve<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<p>\u251c\u2500\u2500 api<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 access.py (\u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430)<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 config.py (\u043e\u0431\u0449\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438)<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 crud.py (\u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432 \u0411\u0414)<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 __init__.py (\u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u0435\u0439)<\/p>\n<p>\u2502 \u00a0 \u2514\u2500\u2500 log.py (\u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432 \u043b\u043e\u0433)<\/p>\n<p>\u251c\u2500\u2500 data.sqlite (\u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445)<\/p>\n<p>\u251c\u2500\u2500 main.py (\u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0441\u043a\u0440\u0438\u043f\u0442\u0430)<\/p>\n<p>\u2514\u2500\u2500 readme.md<\/p>\n<p>\u2514\u2500\u2500app.log (\u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430)<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0444\u0430\u0439\u043b\u0430 api\/config.py<\/p>\n<pre><code class=\"python\">DB_NAME = 'data.sqlite' ACCESS_TABLE = 'users_access' BARIERS_TABLE = 'barriers' USER_TABLE = 'users' LOGGING = { \u00a0\u00a0\u00a0'version': 1, \u00a0\u00a0\u00a0'disable_existing_loggers': False, \u00a0\u00a0\u00a0'formatters': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'simple': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s' \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0'handlers': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'file': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'class': 'logging.FileHandler', \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'filename': 'app.log', \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'formatter': 'simple' \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0},  \u00a0\u00a0\u00a0'loggers': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'myapp': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'handlers': ['file'], \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'level': 'INFO', \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'propagate': False \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0} } all = [\"DB_NAME\", \"ACCESS_TABLE\", \"BARIERS_TABLE\", \"USER_TABLE\", \"LOGGING\"]<\/code><\/pre>\n<p>\u0412 \u043d\u0435\u043c \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u0430\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0438\u043f\u043e\u0432\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043b\u043e\u0433\u043e\u0432 \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 logging.<\/p>\n<p>\u041d\u0435 \u043e\u0442\u0445\u043e\u0434\u044f \u043e\u0442 \u043a\u0430\u0441\u0441\u044b, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a api\/logging.py<\/p>\n<pre><code class=\"python\">from fastapi import APIRouter, Body from typing import Any from . import config import logging.config  logging.config.dictConfig(config.LOGGING) logger = logging.getLogger('myapp') router = APIRouter(tags=[\"Logs\"])  @router.post('\/logs') async def get_body(body: Any = Body(None)):    \"\"\"    Create log for MTC Exolve events.    \"\"\"    logger.info(f'log endpoint was called. body: {body}')    return body<\/code><\/pre>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043b\u043e\u0433\u0433\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445.<br \/>\u0410 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0433\u0440\u0443\u043f\u043f\u0443 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 API (router), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435\u0433\u043e 1 POST \u043c\u0435\u0442\u043e\u0434\u00a0<\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0438\u0448\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043b\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<br \/>\u041e\u043d \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043b\u0438\u0431\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043b\u043e\u0433\u043e\u0432, \u043b\u0438\u0431\u043e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043e\u0442 \u041c\u0422\u0421 Exolve.<\/p>\n<p>\u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0440\u0430\u0434\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0432\u0441\u0435 \u0438 \u0437\u0430\u0442\u0435\u044f\u043b \u2013 \u0441\u043a\u0440\u0438\u043f\u0442\u0443 api\/access.py<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0441\u043f\u0440\u044f\u0447\u0443 \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from fastapi import APIRouter, HTTPException,  Body from pydantic import BaseModel from typing import  List,  Union, Any import sqlite3  from .config import * from .log import logger  EVENT_URL = \"&lt;url or IP&gt;\/logs\" CLIENT_ID = \"MTC Exolve client ID\" DISPLAY_NUMBER  = \"MTC Exolve phone number\"  class FollowMeRule(BaseModel):    I_FOLLOW_ORDER: str    ACTIVE: str    NAME: str    REDIRECT_NUMBER: str    PERIOD: str    PERIOD_DESCRIPTION: str    TIMEOUT: str  class FollowMeStruct(BaseModel):    List[FollowMeRule]   class Result(BaseModel):    redirect_type: int    event_URL: str    client_id: str    event_extended: str    masking: str    display_number: str    followme_struct: List[Union[int, List[FollowMeRule]]]   class ExolveResponse(BaseModel):    id: int    jsonrpc: str    result: Result  def open_barriers(phone):    connection = sqlite3.connect(DB_NAME)    cursor = connection.cursor()    cursor.execute(f'''SELECT phone from {BARIERS_TABLE} as b    JOIN {ACCESS_TABLE} as u on b.zone = u.barrier_zone    where u.user_phone = {phone} ''')    column_names = [col[0] for col in cursor.description]    rows = cursor.fetchall()    response = [dict(zip(column_names, row)) for row in rows]    connection.close()    return response  router = APIRouter(tags=[\"Access control\"])  @router.post(\"\/access\/\", response_model=ExolveResponse) async def response_to_exolve(body: Any = Body(None)):    \"\"\"    Get response to MTC Exolve for redirect phone call to barrier GSM \\n (s.a [documentation](https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=106332539))    \"\"\"    if 'params' in body and 'numberA' in body['params']:        user_phone = body[\"params\"][\"numberA\"]    else:        raise HTTPException(status_code=400, detail=\"Bad request.Filed params.numberA required\")    barrier_phones =  open_barriers(user_phone)    if (barrier_phones == None):        raise HTTPException(status_code=403, detail=\"Access to barriers not allowed\")    followme_struct = []    for i in range(0, len(barrier_phones) ) :        row = barrier_phones[i]        followme_struct.append(            {                \"I_FOLLOW_ORDER\": str(i+1),                \"ACTIVE\": \"Y\",                \"NAME\": \"BARRIER_PHONE\",                \"REDIRECT_NUMBER\": str(row[\"phone\"]),                \"PERIOD\": \"always\",                \"PERIOD_DESCRIPTION\": \"always\",                \"TIMEOUT\": \"30\"            })        # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 Result    result_object = Result(        redirect_type=\"3\",        event_URL=EVENT_URL ,        client_id= CLIENT_ID,        event_extended=\"N\",        masking= \"Y\",        display_number= DISPLAY_NUMBER,        followme_struct=[len(followme_struct),followme_struct]    )    exolve_response_object = ExolveResponse(            id=1,            jsonrpc=\"2.0\",            result=result_object    )    logger.info(f'barriers {barrier_phones} try to open for {user_phone}')    return exolve_response_object<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b:<\/p>\n<pre><code class=\"python\">from fastapi import APIRouter, HTTPException,  Body from pydantic import BaseModel from typing import  List,  Union, Any import sqlite3  from .config import * from .log import logger EVENT_URL = \"&lt;url or IP&gt;\/logs\" CLIENT_ID = \"MTC Exolve client ID\" DISPLAY_NUMBER  = \"MTC Exolve phone number\"<\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430. \u041f\u043e \u0441\u0443\u0442\u0438 \u043c\u044b \u043a\u0430\u043a \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u0443\u044e \u0432 <a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=106332539#id-1.%D0%92%D0%B7%D0%B0%D0%B8%D0%BC%D0%BE%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B5%D0%B2%D0%BC%D0%BE%D0%BC%D0%B5%D0%BD%D1%82%D0%B2%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B5%D0%B3%D0%BE%D0%B2%D1%8B%D0%B7%D0%BE%D0%B2%D0%B0(%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F%D0%BF%D0%B5%D1%80%D0%B5%D0%B0%D0%B4%D1%80%D0%B5%D1%81%D0%B0%D1%86%D0%B8%D1%8F%D0%BF%D0%BEAPI)-%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D0%B0%D0%BE%D1%82API%D0%BA%D0%BB%D0%B8%D0%B5%D0%BD%D1%82%D0%B0\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>.<\/p>\n<pre><code class=\"python\">class FollowMeRule(BaseModel):    I_FOLLOW_ORDER: str    ACTIVE: str    NAME: str    REDIRECT_NUMBER: str    PERIOD: str    PERIOD_DESCRIPTION: str    TIMEOUT: str   class FollowMeStruct(BaseModel):    List[FollowMeRule]    class Result(BaseModel):    redirect_type: int    event_URL: str    client_id: str    event_extended: str    masking: str    display_number: str    followme_struct: List[Union[int, List[FollowMeRule]]]    class ExolveResponse(BaseModel):    id: int    jsonrpc: str    result: Result <\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044e \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043f\u043e\u0437\u0432\u043e\u043d\u0438\u0432\u0448\u0435\u0433\u043e \u043d\u0430 \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430.<\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f open_barriers \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e \u0442\u0430\u0431\u043b\u0438\u0446\u0435 users_access \u043a\u0430\u043a\u0438\u0435 \u0437\u043e\u043d\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e, \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u0435\u0442 \u0438\u0445 \u0441 \u043d\u043e\u043c\u0435\u0440\u0430\u043c\u0438 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u0432 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b barriers, \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u0445 \u0432 \u0432\u0438\u0434\u0435 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<p>\u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u00a0 \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0432\u044b\u043d\u043e\u0441\u0438\u0442\u044c \u0435\u0451 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0447\u0442\u0435\u043d\u0438\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.<\/p>\n<pre><code class=\"python\">def open_barriers(phone):    connection = sqlite3.connect(DB_NAME)    cursor = connection.cursor()    cursor.execute(f'''SELECT phone from {BARIERS_TABLE} as b    JOIN {ACCESS_TABLE} as u on b.zone = u.barrier_zone    where u.user_phone = {phone} ''')    column_names = [col[0] for col in cursor.description]    rows = cursor.fetchall()    response = [dict(zip(column_names, row)) for row in rows]    connection.close()    return response<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 POST \/access, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 MTC Exolve \u043f\u0440\u0438 \u0437\u0432\u043e\u043d\u043a\u0435.<\/p>\n<pre><code class=\"python\">router = APIRouter(tags=[\"Access control\"]) @router.post(\"\/access\/\", response_model=ExolveResponse) async def response_to_exolve(body: Any = Body(None)):    \"\"\"    Get response to MTC Exolve for redirect phone call to barrier GSM \\n (s.a [documentation](https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=106332539))    \"\"\"    if 'params' in body and 'numberA' in body['params']:        user_phone = body[\"params\"][\"numberA\"]    else:        raise HTTPException(status_code=400, detail=\"Bad request.Filed params.numberA required\")    barrier_phones =  open_barriers(user_phone)    if (barrier_phones == None):        raise HTTPException(status_code=403, detail=\"Access to barriers not allowed\")    followme_struct = []    for i in range(0, len(barrier_phones) ) :        row = barrier_phones[i]        followme_struct.append(            {                \"I_FOLLOW_ORDER\": str(i+1),                \"ACTIVE\": \"Y\",                \"NAME\": \"BARRIER_PHONE\",                \"REDIRECT_NUMBER\": str(row[\"phone\"]),                \"PERIOD\": \"always\",                \"PERIOD_DESCRIPTION\": \"always\",                \"TIMEOUT\": \"30\"            })        # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 Result    result_object = Result(        redirect_type=\"3\",        event_URL=EVENT_URL ,        client_id= CLIENT_ID,        event_extended=\"N\",        masking= \"Y\",        display_number= DISPLAY_NUMBER,        followme_struct=[len(followme_struct),followme_struct]    )    exolve_response_object = ExolveResponse(            id=1,            jsonrpc=\"2.0\",            result=result_object    )    logger.info(f'barriers {barrier_phones} try to open for {user_phone}')    return exolve_response_object<\/code><\/pre>\n<p>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u0443\u043a\u0430\u0437\u0430\u043d \u043b\u0438 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u043b\u0441\u044f \u0437\u0432\u043e\u043d\u043e\u043a. \u041f\u043e \u0438\u0434\u0435\u0435 \u043e\u043d \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u043d \u043f\u0440\u0438 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b, \u043d\u043e \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u044d\u0442\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u0432, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 open_barrier.<\/p>\n<p>\u0418 \u0443\u0436\u0435 \u043d\u0430 \u0431\u0430\u0437\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<p>\u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435, \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0432 \u0448\u0430\u0431\u043b\u043e\u043d.<\/p>\n<p>\u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u0432 \u0446\u0438\u043a\u043b\u0435 \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u0435\u0440\u043d\u0443\u043b\u0430\u0441\u044c \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u0438\u0437\u043c\u0435\u043d\u044f\u044f \u043b\u0438\u0448\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b <code>I_FOLLOW_ORDER<\/code> \u0438 <code>REDIRECT_NUMBER<\/code><\/p>\n<pre><code class=\"python\">       followme_struct.append(            {                \"I_FOLLOW_ORDER\": \u201c\u041f\u041e\u0420\u042f\u0414\u041a\u041e\u0412\u042b\u0419 \u041d\u041e\u041c\u0415\u0420 \u0422\u0415\u041b\u0415\u0424\u041e\u041d\u0410 \u0414\u041b\u042f \u0412\u042b\u0417\u041e\u0412\u0410\u201d,                \"ACTIVE\": \"Y\",                \"NAME\": \"BARRIER_PHONE\",                \"REDIRECT_NUMBER\": \u201c\u041d\u041e\u041c\u0415\u0420 \u0422\u0415\u041b\u0415\u0424\u041e\u041d\u0410 \u0412 \u0428\u041b\u0410\u0413\u0411\u0410\u0423\u041c\u0415\u201d,                \"PERIOD\": \"always\",                \"PERIOD_DESCRIPTION\": \"always\",                \"TIMEOUT\": \"30\"            }) <\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0431\u0435\u0440\u0435\u043c \u043a\u0430\u043a \u043c\u0430\u0442\u0440\u0435\u0448\u043a\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <code>result_object<\/code>.<\/p>\n<p>\u0412 \u043d\u0435\u0439 \u043c\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u043d\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430: <code>followme_struct=[<strong>len<\/strong>(followme_struct),followme_struct]<\/code><\/p>\n<p><code>len(followme_struct)<\/code> \u2013 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u043e\u043c\u0435\u0440\u043e\u0432, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0437\u043e\u0432.\u00a0<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u0430\u043a\u0443\u0435\u043c \u0442\u0440\u0435\u0442\u0438\u0439 \u0441\u043b\u043e\u0439 \u043c\u0430\u0442\u0440\u0435\u0448\u043a\u0438:<\/p>\n<pre><code class=\"python\">\u00a0\u00a0\u00a0exolve_response_object = ExolveResponse( \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0id=1, \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0jsonrpc=\"2.0\", \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0result=result_object \u00a0\u00a0\u00a0)<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043b\u043e\u0433 \u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c(\u044b):<\/p>\n<p><code>logger.<strong>info<\/strong>(f'barriers {barrier_phones} try to open for {user_phone}')<\/code><\/p>\n<p>\u0418 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0442\u0432\u0435\u0442:<\/p>\n<p><code>return exolve_response_obje<\/code>ct<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"http:\/\/main.py\">main.py<\/a> \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434 \u0432 \u0434\u0435\u043b\u0435<\/p>\n<pre><code>from fastapi import FastAPI from api import crud, access, log app = FastAPI( title=\"API for bariier control via MTC Exolve\",    description=\"This API requires an API key in the X-API-Key header demo key is 12345\",    version=\"1.0.0\")  app.include_router(access.router) # Use the router app.include_router(log.router) # Use the router app.include_router(crud.router) # Use the router<\/code><\/pre>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0432 API \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (app = FastAPI).<\/p>\n<p>\u0418 \u0434\u0430\u043b\u0435\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043a \u043d\u0435\u0439 \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u043e\u0443\u0442\u0435\u0440\u044b.<\/p>\n<p>\u041f\u0443\u0441\u0442\u044c \u0432\u0430\u0441 \u043d\u0435 \u0441\u043c\u0443\u0449\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0435\u0449\u0435 \u043d\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438 \u0440\u043e\u0443\u0442\u0435\u0440 \u00abcrud\u00bb. \u042d\u0442\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0432\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u044b, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u043b\u0438 \u0437\u0430\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441\u00a0 \u00abcrud\u00bb.<\/p>\n<p><a class=\"anchor\" name=\"a5\" id=\"a5\"><\/a><\/p>\n<h2>\u0418\u0442\u043e\u0433\u0438<\/h2>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439<\/p>\n<p><code>uvicorn app.main:app<\/code><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043a\u0430\u043a \u0438 \u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0435\u0441\u044c \u0441 FastAPI, \u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0441\u044f \u0441\u043e <a href=\"https:\/\/habr.com\/ru\/companies\/amvera\/articles\/826196\/\">\u0441\u0442\u0430\u0442\u044c\u0435\u0439 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u044b \u0430\u0437\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0438\u043c.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0441\u0435\u0440\u0432\u0438\u0441 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443<\/p>\n<p><a href=\"http:\/\/127.0.0.1:8000\/docs\/\/\">http:\/\/127.0.0.1:8000\/docs\/\/<\/a> <\/p>\n<p>\u0414\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043a\u0440\u044b\u0442\u044c\u0441\u044f Swagger. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/276\/3da\/9e8\/2763da9e8bb6b3a1aea2453ef5fb6067.png\" alt=\"Swagger \u0441\u0435\u0440\u0432\u0438\u0441\u0430\" title=\"Swagger \u0441\u0435\u0440\u0432\u0438\u0441\u0430\" width=\"1440\" height=\"922\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/276\/3da\/9e8\/2763da9e8bb6b3a1aea2453ef5fb6067.png\"\/><\/p>\n<div><figcaption>Swagger \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043b\u043e\u0433\u0430\u0445:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cb1\/b7c\/e81\/cb1b7ce8132aba362ad9bcce885902de.png\" alt=\"\u0412\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.\" title=\"\u0412\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.\" width=\"1274\" height=\"1053\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cb1\/b7c\/e81\/cb1b7ce8132aba362ad9bcce885902de.png\"\/><\/p>\n<div><figcaption>\u0412\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 app.log \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0437\u0430\u043f\u0438\u0441\u044c<\/p>\n<p><code>2025-03-23 16:53:35,382 - myapp - INFO - log endpoint was called. body: \u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440<\/code><\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0437\u0432\u043e\u043d\u043a\u0430 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043c\u0438\u0440.<\/p>\n<p>\u041b\u0438\u0447\u043d\u043e \u044f \u0430\u0440\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u043d\u0435\u0434\u043e\u0440\u043e\u0433\u043e\u0439 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u0435\u0433\u043e <a href=\"https:\/\/codelab.pro\/podrobnyj-gajd-po-deployu-fastapi-na-servere\/\">\u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438<\/a>.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c \u043d\u0430 \u0430\u0434\u0440\u0435\u0441<\/p>\n<p><code>http:\/&lt;\u0412\u0430\u0448 IP \u0438\u043b\u0438 \u0434\u043e\u043c\u0435\u043d&gt;\/access\/<\/code> \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c body:<\/p>\n<pre><code class=\"json\">{    \"id\": \"1\",    \"jsonrpc\": \"2.0\",    \"method\": \"getcontrolcallfollowme\",    \"params\": {        \"h323_conf_id\": \" BC5F236C 5AD211E9 81BA5CB9 01FED6FC\",        \"numberA\": \"79123456784\",        \"sip_id\": \"79123456785\"    } }<\/code><\/pre>\n<p>\u0412\u0435\u0440\u043d\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043e\u0442\u0432\u0435\u0442:<\/p>\n<pre><code class=\"json\">{   \"id\": 1,   \"jsonrpc\": \"2.0\",   \"result\": {     \"redirect_type\": 3,     \"event_URL\": \"http:\/\/62.113.44.250\/logs\",     \"client_id\": \"1215882\",     \"event_extended\": \"N\",     \"masking\": \"Y\",     \"display_number\": \"79841860477\",     \"followme_struct\": [       2,       [         {           \"I_FOLLOW_ORDER\": \"1\",           \"ACTIVE\": \"Y\",           \"NAME\": \"BARRIER_PHONE\",           \"REDIRECT_NUMBER\": \"79123456782\",           \"PERIOD\": \"always\",           \"PERIOD_DESCRIPTION\": \"always\",           \"TIMEOUT\": \"30\"         },         {           \"I_FOLLOW_ORDER\": \"2\",           \"ACTIVE\": \"Y\",           \"NAME\": \"BARRIER_PHONE\",           \"REDIRECT_NUMBER\": \"79123456781\",           \"PERIOD\": \"always\",           \"PERIOD_DESCRIPTION\": \"always\",           \"TIMEOUT\": \"30\"         }       ]     ]   } }<\/code><\/pre>\n<p>\u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e MTC Exolve \u043f\u043e\u0437\u0432\u043e\u043d\u0438\u0442 \u043d\u0430 \u043e\u0431\u0430 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u0438 \u043e\u043d\u0438 \u043e\u0431\u0430 \u043e\u0442\u043a\u0440\u043e\u044e\u0442\u0441\u044f.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0449\u0435 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0441\u0438\u043b\u044b, \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0440\u043e\u0431\u0435\u0436\u0438\u043c\u0441\u044f \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c CRUD.<\/p>\n<p><a class=\"anchor\" name=\"a6\" id=\"a6\"><\/a><\/p>\n<h2>\u0411\u043e\u043d\u0443\u0441 \u2013 CRUD API<\/h2>\n<p>\u0415\u0449\u0435 \u0440\u0430\u0437 \u043d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432\u0441\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 <a href=\"https:\/\/github.com\/bosonbeard\/mts-habr\/tree\/main\/barrier_control\">GitHub<\/a>.<\/p>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 \/api\/crud.py \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0447\u0442\u0435\u043d\u0438\u044f, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/aea\/83f\/a24\/aea83fa24f4aab7152def0f1cca8e4f6.png\" alt=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API. \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 CRUD\" title=\"\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API. \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 CRUD\" width=\"1142\" height=\"930\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/aea\/83f\/a24\/aea83fa24f4aab7152def0f1cca8e4f6.png\"\/><\/p>\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API. \u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 CRUD<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u043c\u043e\u0434\u0443\u043b\u044f \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u043e\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from fastapi import APIRouter, HTTPException,  Depends,  Body from .config import * from pydantic import BaseModel, Field from typing import Optional, List, Annotated import sqlite3 from .log import logger from fastapi.security import APIKeyHeader   API_KEY = \"12345\"  # Replace with your key  api_key_header = APIKeyHeader(name=\"X-API-Key\", auto_error=True, description=\"API Key required for access\")   async def get_api_key(api_key_header: Annotated[str, Depends(api_key_header)]):    \"\"\"    Dependency to validate the API key from the header.    \"\"\"    if api_key_header == API_KEY:        return api_key_header    else:        raise HTTPException(status_code=403, detail=\"Invalid API Key\")  class Message(BaseModel):    message:str   class User(BaseModel):    id: int    phone: int    name: str    last_name: str    position: Optional[str] = None   class CreatedUser(BaseModel):    phone: int = Field(...,  description=\"User's phone.\")    name: str = Field(...,  description=\"User's name.\")    last_name: str = Field(...,  description=\"User's last name.\")    last_name: str    position: Optional[str] = Field(None, description=\"user position (optional).\")   class CreatedBarrier(BaseModel):    zone: int = Field(...,  description=\"Security zone (location of the barrier on the site plan).\")    phone: int = Field(...,  description=\"Phone of GSM module for opening barrier.\")    class Barrier(BaseModel):    id: int    zone: int    phone: int   class Access(BaseModel):    user_phone: int    barrier_zone: int   def read_tables(table, id=None):    \"\"\"    Function for read users and barriers from db.    \"\"\"    connection = sqlite3.connect(DB_NAME)    cursor = connection.cursor()    where = \"\"    if id:        where = f\" WHERE `id` = {id}\"    cursor.execute(f'SELECT * FROM {table} {where}')    column_names = [col[0] for col in cursor.description]    rows = cursor.fetchall()    response = [dict(zip(column_names, row)) for row in rows]    connection.close()    if not response:        return None    return response[0] if id else response   def update_tables(table, operation, data=None, id=None):    \"\"\"    Function for read users, barriers, and accesses from DB.    \"\"\"    try:        connection = sqlite3.connect(DB_NAME)        cursor = connection.cursor()        sql_data = ()        fields = {            \"users\":(\"phone\", \"name\", \"last_name\", \"position\"),            \"barriers\":(\"zone\", \"phone\"),            \"users_access\":(\"user_phone\", \"barrier_zone\")            }        if data:            match table:                case \"users\":                    sql_data = (data.phone, data.name, data.last_name, data.position)                case \"barriers\":                    sql_data = (data.zone, data.phone)                case \"users_access\":                    sql_data = (data.user_phone, data.barrier_zone)        match operation:            case \"create\":                values=[]                for field in fields[table]:                     values.append(f'?')                result_string = ', '.join(values)                sql = f'UPDATE {table} SET {result_string} Where id = {id}'                sql = f'INSERT INTO {table} {fields[table]} VALUES ({result_string})'                cursor.execute(sql, sql_data)                connection.commit()            case \"delete\":                sql =\"\"                if id:                    sql = f'DELETE FROM {table}  WHERE id = {id}'                elif data:                    sql = f'DELETE FROM {table}  WHERE user_phone = {data.user_phone} AND barrier_zone = {data.barrier_zone} '                cursor.execute(sql)                connection.commit()            case \"update\":                update_fields = []                for field in fields[table]:                     update_fields.append(f'{field} = ?')                result_string = ', '.join(update_fields)                sql = f'UPDATE {table} SET {result_string} Where id = {id}'                sql_data = tuple(data.model_dump().values())                cursor.execute(sql, sql_data)                connection.commit()            case None:                return None    except sqlite3.Error as e:            print(f\"Error: {e}\")            return None    finally:            if connection:                connection.close()    return cursor.lastrowid  router = APIRouter(tags=[\"CRUD\"])  @router.get(\"\/bariers\/\", response_model=List[Barrier]) async def list_bariers(api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    List all barriers.    \"\"\"    response = read_tables(BARIERS_TABLE)    return response   @router.get(\"\/barrier\/{barrier_id}\", response_model=Barrier) async def list_barrier(barrier_id: int, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Get a barrier with specific id.    \"\"\"    response = read_tables(BARIERS_TABLE, barrier_id)    if not response:        raise HTTPException(status_code=404, detail=\"Barrier not found\")    return response  @router.post(\"\/barriers\/\", response_model=Message) async def create_barrier(barrier: CreatedBarrier, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Creates a new barrier.    \"\"\"    result = update_tables(BARIERS_TABLE, \"create\", data=barrier)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'barrier created {barrier}')    return {\"message\": f\"created barrier with id = {result}\"}   @router.delete(\"\/barriers\/{barrier_id}\", response_model=Message) async def delete_barrier(barrier_id:int, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Delete a barrier with specific id.    \"\"\"    result = update_tables(BARIERS_TABLE, \"delete\", None, barrier_id)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'barrier {barrier_id} deleted')    return {\"message\":\"ok\"}  @router.patch(\"\/barriers\/{barrier_id}\", response_model=Message) async def edit_barrier(barrier_id:int, barrier:CreatedBarrier,api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Update a barrier with specific id (fill in all the request attributes).    \"\"\"    result = update_tables(BARIERS_TABLE, \"update\", barrier, barrier_id)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'barrier {barrier_id} updated {barrier}')    return {\"message\":\"ok\"}   @router.get(\"\/accesses\/\", response_model=List[Access]) async def list_accesses(api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    List accesses (user to barrier).    \"\"\"    response = read_tables(ACCESS_TABLE)    return response  @router.post(\"\/accesses\/\", response_model=Message) async def create_access(access: Access, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Creates a new access (user to barrier).    \"\"\"    result = update_tables(ACCESS_TABLE, \"create\", data=access)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'user access created {access}')    return {\"message\": f\"created access with id = {result}\"}   @router.delete(\"\/accesses\/\", response_model=Message) async def delete_user(access:Access, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Delete access (user to barrier).    \"\"\"    result = update_tables(ACCESS_TABLE, \"delete\",access, None)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'user access deleted {access}')    return {\"message\":\"ok\"}  @router.get(\"\/users\/\", response_model=List[User]) async def list_users(api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    List all users.    \"\"\"    response = read_tables(USER_TABLE)    return response     @router.get(\"\/users\/{user_id}\", response_model=User) async def list_user(user_id: int, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Get a user with specific id.    \"\"\"    response = read_tables(USER_TABLE, user_id)    if not response:        raise HTTPException(status_code=404, detail=\"User not found\")    return response   @router.post(\"\/users\/\", response_model=Message) async def create_user(user: CreatedUser, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Creates a new user.    \"\"\"    result = update_tables(USER_TABLE, \"create\", data=user)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'user created {user}')    return {\"message\": f\"created  user with id {result}\"}   @router.delete(\"\/users\/{user_id}\", response_model=Message) async def delete_user(user_id:int, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Delete a user with specific id.    \"\"\"    result = update_tables(USER_TABLE, \"delete\", None, user_id)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'user_id = {user_id} deleted')    return {\"message\":\"ok\"}     @router.patch(\"\/users\/{user_id}\", response_model=Message) async def edit_user(user_id:int, user:CreatedUser, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Update a user      with specific id (fill in all the request attributes).    \"\"\"    result = update_tables(USER_TABLE, \"update\", user, user_id)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'user_id = {user_id} updated {user}')    return {\"message\":\"ok\"}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043b\u0438\u0448\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043f\u0430\u0440\u0443 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a \u043d\u0438\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f.<\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <strong>read_tables <\/strong>\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0432 \u0411\u0414 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u042f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u0437 \u043a\u0430\u043a\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0447\u0438\u0442\u0430\u0442\u044c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c id, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 (\u044d\u0442\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 \u0447\u0442\u0435\u043d\u0438\u044f \u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0432\u044b\u0431\u043e\u0440\u043a\u0438).\u00a0<\/p>\n<pre><code class=\"python\">def read_tables(table, id=None):    \"\"\"    Function for read users and barriers from db.    \"\"\"    connection = sqlite3.connect(DB_NAME)    cursor = connection.cursor()    where = \"\"    if id:        where = f\" WHERE `id` = {id}\"    cursor.execute(f'SELECT * FROM {table} {where}')    column_names = [col[0] for col in cursor.description]    rows = cursor.fetchall()    response = [dict(zip(column_names, row)) for row in rows]    connection.close()    if not response:        return None    return response[0] if id else response<\/code><\/pre>\n<p>\u0410 \u0432\u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <strong>update_tables <\/strong>\u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u0430\u044f. \u042f \u0442\u043e\u0436\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0451 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445.<\/p>\n<pre><code class=\"python\">def update_tables(table, operation, data=None, id=None):    \"\"\"    Function for read users, barriers, and accesses from DB.    \"\"\"    try:        connection = sqlite3.connect(DB_NAME)        cursor = connection.cursor()        sql_data = ()        fields = {            \"users\":(\"phone\", \"name\", \"last_name\", \"position\"),            \"barriers\":(\"zone\", \"phone\"),            \"users_access\":(\"user_phone\", \"barrier_zone\")            }        if data:            match table:                case \"users\":                    sql_data = (data.phone, data.name, data.last_name, data.position)                case \"barriers\":                    sql_data = (data.zone, data.phone)                case \"users_access\":                    sql_data = (data.user_phone, data.barrier_zone)        match operation:            case \"create\":                values=[]                for field in fields[table]:                     values.append(f'?')                result_string = ', '.join(values)                sql = f'UPDATE {table} SET {result_string} Where id = {id}'                sql = f'INSERT INTO {table} {fields[table]} VALUES ({result_string})'                cursor.execute(sql, sql_data)                connection.commit()            case \"delete\":                sql =\"\"                if id:                    sql = f'DELETE FROM {table}  WHERE id = {id}'                elif data:                    sql = f'DELETE FROM {table}  WHERE user_phone = {data.user_phone} AND barrier_zone = {data.barrier_zone} '                cursor.execute(sql)                connection.commit()            case \"update\":                update_fields = []                for field in fields[table]:                     update_fields.append(f'{field} = ?')                result_string = ', '.join(update_fields)                sql = f'UPDATE {table} SET {result_string} Where id = {id}'                sql_data = tuple(data.model_dump().values())                cursor.execute(sql, sql_data)                connection.commit()            case None:                return None    except sqlite3.Error as e:            print(f\"Error: {e}\")            return None    finally:            if connection:                connection.close()    return cursor.lastrowid<\/code><\/pre>\n<p>\u0418 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u0434 \u043f\u0430\u0440\u044b \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432\u044b\u0448\u0435\u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u0445. \u043c\u0435\u0442\u043e\u0434\u0430 GET \/barriers\/. \u041f\u043e \u0441\u0443\u0442\u0438 \u043e\u043d \u043b\u0438\u0448\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e \u0432\u0441\u0435\u043c \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u043c.<\/p>\n<pre><code class=\"python\">router = APIRouter(tags=[\"CRUD\"])   @router.get(\"\/bariers\/\", response_model=List[Barrier]) async def list_bariers(api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    List all barriers.    \"\"\"    response = read_tables(BARIERS_TABLE)    return response<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0 a<code>pi_key: Annotated[str, Depends(get_api_key)<\/code>, \u044f \u0440\u0435\u0448\u0438\u043b\u00a0 \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434\u044b CRUD \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0438\u043c \u043d\u0443\u0436\u0435\u043d \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 12345. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0435\u0451 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0437\u0443\u0447\u0438\u0442\u0435 \u043f\u043e\u043b\u043d\u044b\u0439 \u043b\u0438\u0441\u0442\u0438\u043d\u0433, \u0442\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u0442\u0435\u0441\u044c \u0432 \u0442\u0438\u043f\u043e\u0432\u043e\u043c \u043a\u043e\u0434\u0435.<\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3c8\/d34\/fc6\/3c8d34fc661c343c1b445b1364649b71.png\" alt=\"\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u0435\u0442\u043e\u0434\u0430 GET \/barriers \u0432 Swagger\" title=\"\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u0435\u0442\u043e\u0434\u0430 GET \/barriers \u0432 Swagger\" width=\"1276\" height=\"857\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3c8\/d34\/fc6\/3c8d34fc661c343c1b445b1364649b71.png\"\/><\/p>\n<div><figcaption>\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u0435\u0442\u043e\u0434\u0430 GET \/barriers \u0432 Swagger<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043e \u0431\u0430\u0440\u044c\u0435\u0440\u0435 POST \/barriers\/. \u041c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043d\u043e\u043c\u0435\u0440 \u0437\u043e\u043d\u044b \u0438 \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u0432\u043d\u0443\u0442\u0440\u0438 GSM-\u043c\u043e\u0434\u0443\u043b\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0430, \u0432\u0435\u0440\u043d\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 id \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 barrires.<\/p>\n<pre><code class=\"python\">@router.post(\"\/barriers\/\", response_model=Message) async def create_barrier(barrier: CreatedBarrier, api_key: Annotated[str, Depends(get_api_key)]):    \"\"\"    Creates a new barrier.    \"\"\"    result = update_tables(BARIERS_TABLE, \"create\", data=barrier)    if result == None:         raise HTTPException(status_code=400, detail=\"Bad request\")    logger.info(f'barrier created {barrier}')    return {\"message\": f\"created barrier with id = {result}\"}<\/code><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1eb\/729\/f93\/1eb729f939d434317fa7127ceb70a4ff.png\" alt=\"\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u0435\u0442\u043e\u0434\u0430 POST \/barriers \u0432 Swagger\" title=\"\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u0435\u0442\u043e\u0434\u0430 POST \/barriers \u0432 Swagger\" width=\"1144\" height=\"1024\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1eb\/729\/f93\/1eb729f939d434317fa7127ceb70a4ff.png\"\/><\/p>\n<div><figcaption>\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u0435\u0442\u043e\u0434\u0430 POST \/barriers \u0432 Swagger<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430, \u043d\u043e \u0438 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 \u043f\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c.<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0432 \u0441\u0435\u0440\u0432\u0438\u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e, \u0447\u0442\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u0434\u043e \u043a\u043e\u043d\u0446\u0430! \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u044b\u043b\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439. \u0411\u0443\u0434\u0443 \u0440\u0430\u0434 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u0441\u044f \u0441 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/893432\/\"> https:\/\/habr.com\/ru\/articles\/893432\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a, \u043f\u0440\u043e\u043a\u043b\u044f\u0442\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0444\u0440\u0430\u0437\u044b\u00a0 \u00ab\u0442\u044b\u0436 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u2026\u00bb, \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u0440\u0435\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438 \u043c\u0435\u043d\u044f. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u0441\u043f\u0440\u043e\u0441\u0438\u043b\u0438 \u0441\u043e\u0432\u0435\u0442\u0430, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u044f \u043d\u0443\u0436\u043d\u044b\u0445 \u043b\u044e\u0434\u0435\u0439 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b\u0441\u044f \u0431\u0435\u0437 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u043d\u0434\u0435\u0440\u0430 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.\u00a0<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u0445\u043e\u0434\u0443 \u044f \u043d\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441, \u043d\u043e \u0437\u0430\u0434\u0430\u0447\u043a\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u043e\u0439, \u0438 \u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u0443\u0447\u0438\u043b \u0432\u043e\u043f\u0440\u043e\u0441.\u00a0<\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u0451\u043b \u0431\u044b\u0441\u0442\u0440\u043e \u2014 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c GSM-\u0440\u0435\u043b\u0435, \u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0438\u043a\u0440\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<p>\u0418 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043c\u0435\u043d\u044f \u043d\u0430\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a <a href=\"https:\/\/exolve.ru\/products\/voice-api\/?utm_source=habr&amp;utm_medium=refferal&amp;utm_campaign=voiceapi_article&amp;utm_content=article_remotecontrol&amp;utm_term=voiceapi_exolve\">\u041c\u0422\u0421 Exolve<\/a>, \u0433\u0440\u0435\u0445 \u0431\u044b\u043b\u043e \u0438\u043c \u043d\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u0422\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 <a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=106332469\">API \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c<\/a> \u0435\u0441\u0442\u044c.<\/p>\n<p><strong>\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/strong><\/p>\n<ul>\n<li>\n<p><a href=\"#a1\">\u0427\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a2\">\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a3\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0423\u0412\u0412 API \u041c\u0422\u0421 Exolve<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a4\">\u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a5\">\u0418\u0442\u043e\u0433\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#a6\">\u0411\u043e\u043d\u0443\u0441 \u2013 CRUD API<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0435\u0441\u0442\u043d\u043e, \u044f \u043d\u0435 \u0437\u043d\u0430\u0442\u043e\u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043b\u044e\u0431\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0438\u043a \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u00abGSM \u043c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u00bb.\u00a0 \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0443 \u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432 \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0438 (\u0440\u0430\u0437\u043c\u044b\u043a\u0430\u043d\u0438\u0438 \u0440\u0435\u043b\u0435) \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0442\u044c \u0438 \u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c.<\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435, \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u043c\u043e\u0436\u043d\u043e \u0438 \u043d\u0435 \u0433\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0437\u0434\u0430\u0442\u044c \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 SIM-\u043a\u0430\u0440\u0442\u044b \u0432 GSM-\u043c\u043e\u0434\u0443\u043b\u0435. \u041d\u043e \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u043d\u043e\u043c\u0435\u0440 \u0441\u0442\u0430\u043d\u0435\u0442 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0442\u0440\u0435\u0442\u044c\u0438\u043c \u043b\u0438\u0446\u0430\u043c? \u041d\u0430\u043c \u044f\u0432\u043d\u043e \u043d\u0443\u0436\u0435\u043d \u0431\u0435\u043b\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043d\u044b\u0445 \u043d\u043e\u043c\u0435\u0440\u043e\u0432. \u041f\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0440\u0435\u0448\u0430\u044e\u0442 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438. \u041d\u043e \u043c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0432 \u0440\u0443\u043a\u0430\u0445 FastAPI. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044e \u0437\u0432\u043e\u043d\u044f\u0449\u0438\u0445 \u0441 \u00ab\u043a\u0430\u0440\u0442\u043e\u0448\u043d\u044b\u043c\u0438 \u0438\u0433\u0440\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u0447\u0438\u043c\u0438 \u0443\u0432\u0435\u0441\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438\u00bb.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0434\u0435\u043b\u0443 \u2013 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0434\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440. \u042f \u043d\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442.\u00a0 \u0417\u0430\u0434\u0430\u0447\u0443 \u044f \u0440\u0435\u0448\u0430\u043b \u0441\u043a\u043e\u0440\u0435\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0438 \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u044b \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u043f\u0440\u043e\u0434\u0443\u043c\u044b\u0432\u0430\u043b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043d\u0430\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043a \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430\u043c \u0441\u0442\u0430\u0442\u044c\u0438, \u043a\u0430\u043a \u043a \u0438\u0441\u0442\u0438\u043d\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u043e\u0439 \u0441\u0440\u0435\u0434\u0435.<\/p>\n<p><a class=\"anchor\" name=\"a1\" id=\"a1\"><\/a><\/p>\n<h2>\u0427\u0442\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c<\/h2>\n<p>\u0424\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0443\u043b\u0430\u0436\u0435\u043d\u044b \u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u0434\u0435\u043b\u0443.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439:<\/p>\n<p><strong>\u041f\u0440\u0435\u0434\u0443\u0441\u043b\u043e\u0432\u0438\u044f.<\/strong><\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e (\u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0434\u0432\u0435) \u0437\u043e\u043d\u044b, \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0435 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u043c\u0438, \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0442\u043e\u0438\u0442 \u0441\u0432\u043e\u0439 GSM-\u043c\u043e\u0434\u0443\u043b\u044c.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0434\u043d\u043e\u0439 \u0438\u043b\u0438 \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u0437\u043e\u043d\u0430\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u0434\u044a\u0435\u0437\u0436\u0430\u0435\u0442 \u043a \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0431\u0438\u0440\u0430\u0435\u0442 \u043d\u043e\u043c\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p>MT\u0421 Exolve \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043d\u0430\u043c \u0432 \u0441\u0435\u0440\u0432\u0438\u0441<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0432 \u043a\u0430\u043a\u0438\u0435 \u0437\u043e\u043d\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u043f\u0440\u043e\u0435\u0437\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0431\u0437\u0432\u043e\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0428\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u044b \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<p><\/p>\n<figure class=\"\">\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u043e\u043c<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"#a2\" id=\"#a2\"><\/a><\/p>\n<h2>\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438\u0437 \u0431\u0435\u043b\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0430 \u044f \u0432\u0437\u044f\u043b SQlite \u0438\u0431\u043e \u0435\u0451 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0430\u043c \u0445\u0432\u0430\u0442\u0438\u0442 \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439, \u0430 \u0435\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u00ab\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u00bb \u0432 Python 3.<\/p>\n<p>\u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u0432\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b:<\/p>\n<ul>\n<li>\n<p>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0432\u043e\u043d\u0438\u0442\u044c \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u043d\u044b\u0439 \u043d\u043e\u043c\u0435\u0440 (users).\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043d\u043e\u043c\u0435\u0440\u0430\u0445 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430\u0445 GSM-\u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0432 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430\u0445 \u0438 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u043c\u044b\u0445 \u0438\u043c\u0438 \u0437\u043e\u043d\u0430\u0445 (barriers).<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0432\u044f\u0437\u0438 \u043c\u043d\u043e\u0433\u0438\u0435-\u043a\u043e-\u043c\u043d\u043e\u0433\u0438\u043c, \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0440\u0435\u0442\u044c\u044e \u0442\u0430\u0431\u043b\u0438\u0447\u043a\u0443 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0438\u043c \u0437\u043e\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u0437\u0434\u0430 (users_access).<\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>ER-\u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\">\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0411\u0414<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u044f \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043b \u043d\u0430 <a href=\"https:\/\/github.com\/bosonbeard\/mts-habr\/tree\/main\/barrier_control\"><strong>GitHub<\/strong><\/a><strong>, <\/strong>\u0432\u043e\u0437\u0434\u0435\u0440\u0436\u0443\u0441\u044c \u043e\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0442\u0430\u0431\u043b\u0438\u0446..<\/p>\n<p>\u041e\u0442\u043c\u0435\u0447\u0443 \u0442\u043e\u043b\u044c\u043a\u043e, \u0447\u0442\u043e \u0432 user_access \u0441\u043e\u0441\u0442\u0430\u0432\u043d\u043e\u0439 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u043e\u0431\u043e\u0438\u0445 \u043f\u043e\u043b\u0435\u0439, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0431\u0430 \u043f\u043e\u043b\u044f \u044d\u0442\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445.\u00a0<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0430 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430.<\/p>\n<p>\u041e\u0434\u0438\u043d \u0434\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0433\u043e\u0441\u0442\u0435\u0439 (#1), \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 (\u21162) \u0434\u043b\u044f \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432.<\/p>\n<figure class=\"\">\n<div><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b barriers<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u0441\u0435 \u0438\u043c\u0435\u043d\u0430 \u0438 \u043d\u043e\u043c\u0435\u0440\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u0432 \u0432\u044b\u0434\u0443\u043c\u0430\u043d\u044b, \u043b\u044e\u0431\u044b\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b.\u00a0<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>\u041e\u0434\u043d\u043e\u0433\u043e \u0433\u043e\u0441\u0442\u044f (Habr) \u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430 (Habra).<\/p>\n<figure class=\"\">\n<div><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0434\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u044b. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c Habr \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0435\u0445\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c, \u0430 Habra \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0435\u0445\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0430.<\/p>\n<figure class=\"\">\n<div><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b users_access<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"a3\" id=\"a3\"><\/a><\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0423\u0412\u0412 API \u041c\u0422\u0421 Exolve<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0432 <a href=\"https:\/\/exolve.ru\/products\/voice-api\/?utm_source=habr&amp;utm_medium=refferal&amp;utm_campaign=voiceapi_article&amp;utm_content=article_remotecontrol&amp;utm_term=voiceapi_exolve\">\u041c\u0422\u0421 Exolve<\/a>. \u042f \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043a \u043d\u0435\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f.<\/p>\n<p><a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=108497488\">\u0421\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>setSipCallControlU<\/code> \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c URL, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 Exolve \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0437\u0430 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0432\u044b\u0437\u043e\u0432\u0430.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441:<\/p>\n<p><a href=\"https:\/\/api.mtt.ru\/ipcr\/\">https:\/\/api.mtt.ru\/ipcr\/<\/a> (\u0443\u043a\u0430\u0437\u0430\u0432 \u0432 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c).<\/p>\n<p>\u0422\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<pre><code class=\"json\">{ \u00a0\u00a0\u00a0\u00a0\"id\":\"1\", \u00a0\u00a0\u00a0\u00a0\"jsonrpc\":\"2.0\", \u00a0\u00a0\u00a0\u00a0\"method\": \"setSipCallControlURL\", \u00a0\u00a0\u00a0\u00a0\"params\": { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"sip_id\": \"\u0412\u0430\u0448 SIP ID (\u043d\u043e\u043c\", \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"url\": \"\u0412\u0430\u0448 URL\" \u00a0\u00a0\u00a0\u00a0} }<\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435\u00a0 <code>sip_id<\/code> \u2013 \u044d\u0442\u043e \u043d\u043e\u043c\u0435\u0440 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0443\u0442 \u0437\u0432\u043e\u043d\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438. \u0410 <code>url<\/code> \u2013 \u044d\u0442\u043e \u0430\u0434\u0440\u0435\u0441 \u043c\u0435\u0442\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043a\u0430\u0436\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0430 &lt;\u0432\u0430\u0448 \u0434\u043e\u043c\u0435\u043d \u0438\u043b\u0438 IP&gt;\/access.<\/p>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0443<a href=\"https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=108497490\">\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0439 \u043d\u043e\u043c\u0435\u0440<\/a>, \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439 \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u043e\u043c\u0435\u0440 \u043f\u043e\u0441\u0442\u0430 \u043e\u0445\u0440\u0430\u043d\u044b.<\/p>\n<p><a class=\"anchor\" name=\"a4\" id=\"a4\"><\/a><\/p>\n<h2>\u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0437\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b Python v. 3.10 \u0438 fastapi v. 0.115, \u043d\u043e \u0434\u0443\u043c\u0430\u044e, \u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0443\u0442 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<p>\u041e\u0441\u0432\u0435\u0436\u0438\u043c \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, \u0441\u0445\u0435\u043c\u0443 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0451 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0421\u0445\u0435\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Exolve<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<p>\u251c\u2500\u2500 api<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 access.py (\u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0448\u043b\u0430\u0433\u0431\u0430\u0443\u043c\u0430)<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 config.py (\u043e\u0431\u0449\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438)<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 crud.py (\u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432 \u0411\u0414)<\/p>\n<p>\u2502 \u00a0 \u251c\u2500\u2500 __init__.py (\u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u0435\u0439)<\/p>\n<p>\u2502 \u00a0 \u2514\u2500\u2500 log.py (\u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0432 \u043b\u043e\u0433)<\/p>\n<p>\u251c\u2500\u2500 data.sqlite (\u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445)<\/p>\n<p>\u251c\u2500\u2500 main.py (\u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0441\u043a\u0440\u0438\u043f\u0442\u0430)<\/p>\n<p>\u2514\u2500\u2500 readme.md<\/p>\n<p>\u2514\u2500\u2500app.log (\u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430)<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0444\u0430\u0439\u043b\u0430 api\/config.py<\/p>\n<pre><code class=\"python\">DB_NAME = 'data.sqlite' ACCESS_TABLE = 'users_access' BARIERS_TABLE = 'barriers' USER_TABLE = 'users' LOGGING = { \u00a0\u00a0\u00a0'version': 1, \u00a0\u00a0\u00a0'disable_existing_loggers': False, \u00a0\u00a0\u00a0'formatters': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'simple': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s' \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0'handlers': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'file': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'class': 'logging.FileHandler', \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'filename': 'app.log', \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'formatter': 'simple' \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0},  \u00a0\u00a0\u00a0'loggers': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'myapp': { \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'handlers': ['file'], \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'level': 'INFO', \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'propagate': False \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}, \u00a0\u00a0\u00a0} } all = [\"DB_NAME\", \"ACCESS_TABLE\", \"BARIERS_TABLE\", \"USER_TABLE\", \"LOGGING\"]<\/code><\/pre>\n<p>\u0412 \u043d\u0435\u043c \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043a\u0440\u0438\u043f\u0442\u0430\u0445, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0438\u043f\u043e\u0432\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043b\u043e\u0433\u043e\u0432 \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 logging.<\/p>\n<p>\u041d\u0435 \u043e\u0442\u0445\u043e\u0434\u044f \u043e\u0442 \u043a\u0430\u0441\u0441\u044b, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a api\/logging.py<\/p>\n<pre><code class=\"python\">from fastapi import APIRouter, Body from typing import Any from . import config import logging.config  logging.config.dictConfig(config.LOGGING) logger = logging.getLogger('myapp') router = APIRouter(tags=[\"Logs\"])  @router.post('\/logs') async def get_body(body: Any = Body(None)):    \"\"\"    Create log for MTC Exolve events.    \"\"\"    logger.info(f'log endpoint was called. body: {body}')    return body<\/code><\/pre>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043b\u043e\u0433\u0433\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445.<br \/>\u0410 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0433\u0440\u0443\u043f\u043f\u0443 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 API (router), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435\u0433\u043e 1 POST \u043c\u0435\u0442\u043e\u0434\u00a0<\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0438\u0448\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043b\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<br \/>\u041e\u043d \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043b\u0438\u0431\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043b\u043e\u0433\u043e\u0432, \u043b\u0438\u0431\u043e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043e\u0442 \u041c\u0422\u0421 Exolve.<\/p>\n<p>\u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0440\u0430\u0434\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0432\u0441\u0435 \u0438 \u0437\u0430\u0442\u0435\u044f\u043b \u2013 \u0441\u043a\u0440\u0438\u043f\u0442\u0443 api\/access.py<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043b\u0438\u0441\u0442\u0438\u043d\u0433 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0441\u043f\u0440\u044f\u0447\u0443 \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from fastapi import APIRouter, HTTPException,  Body from pydantic import BaseModel from typing import  List,  Union, Any import sqlite3  from .config import * from .log import logger  EVENT_URL = \"&lt;url or IP&gt;\/logs\" CLIENT_ID = \"MTC Exolve client ID\" DISPLAY_NUMBER  = \"MTC Exolve phone number\"  class FollowMeRule(BaseModel):    I_FOLLOW_ORDER: str    ACTIVE: str    NAME: str    REDIRECT_NUMBER: str    PERIOD: str    PERIOD_DESCRIPTION: str    TIMEOUT: str  class FollowMeStruct(BaseModel):    List[FollowMeRule]   class Result(BaseModel):    redirect_type: int    event_URL: str    client_id: str    event_extended: str    masking: str    display_number: str    followme_struct: List[Union[int, List[FollowMeRule]]]   class ExolveResponse(BaseModel):    id: int    jsonrpc: str    result: Result  def open_barriers(phone):    connection = sqlite3.connect(DB_NAME)    cursor = connection.cursor()    cursor.execute(f'''SELECT phone from {BARIERS_TABLE} as b    JOIN {ACCESS_TABLE} as u on b.zone = u.barrier_zone    where u.user_phone = {phone} ''')    column_names = [col[0] for col in cursor.description]    rows = cursor.fetchall()    response = [dict(zip(column_names, row)) for row in rows]    connection.close()    return response  router = APIRouter(tags=[\"Access control\"])  @router.post(\"\/access\/\", response_model=ExolveResponse) async def response_to_exolve(body: Any = Body(None)):    \"\"\"    Get response to MTC Exolve for redirect phone call to barrier GSM \\n (s.a [documentation](https:\/\/wiki.exolve.ru\/pages\/viewpage.action?pageId=106332539))    \"\"\"    if 'params' in body and 'numberA' in body['params']:        user_phone = body[\"params\"][\"numberA\"]    else:        raise HTTPException(status_code=400, detail=\"Bad request.Filed params.numberA required\")    barrier_phones =  open_barriers(user_phone)    if (barrier_phones == None):        raise HTTPException(status_code=403, detail=\"Access to barriers not allowed\")    followme_struct = []    for i in range(0, len(barrier_phones) ) :        row = barrier_phones[i]        followme_struct.append(            {                \"I_FOLLOW_ORDER\": str(i+1),                \"ACTIVE\": \"Y\",                \"NAME\": \"BARRIER_PHONE\",                \"REDIRECT_NUMBER\": str(row[\"phone\"]),                \"PERIOD\": \"always\",                \"PERIOD_DESCRIPTION\": \"always\",                \"TIMEOUT\": \"30\"            })        # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 Result    result_object = Result(        redirect_type=\"3\",        event_URL=EVENT_URL ,        client_id= CLIENT_ID,        event_extended=\"N\",        masking=<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-454050","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/454050","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=454050"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/454050\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=454050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=454050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=454050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}