Как оценить свою публикацию?

Близится Новый Год. В Хабаровске он уже наступил, поздравляю!

По традиции, нужно подвести итоги уходящего года, и я решил перечитать свои посты. Перечитать-то перечитал, но как их оценить? Карма? Рейтинг? Просмотры? Слишком сухо и серьезно. Попугаи? Слишком несерьезно. Я решил измерять в Milfgard-ах.


Методика измерения: достаем посты Milfgard, и считаем частоту использования букв. Самый простой аналог фоносемантического анализа.

public static class SymbolsExtractor     {         private static readonly char[] _russianSymbols = "абвгдеёжзиклмнопрстуфхцчшщъыьэюя".ToCharArray(); // 32 русских буквы         public static char[] RussianSymbols => _russianSymbols.ToArray();          public static Dictionary<char, double> SymbolsFrequences(this string text)         {             var symbolsQty = text.ToCharArray().Count(symbol => _russianSymbols.Contains(symbol)); // Длина текста (считаются лишь русские буквы)             double symbolPercentage = 1.00/symbolsQty;               var result = new Dictionary<char, double>();             foreach (char russianSymbol in _russianSymbols)             {                 double inclusions = text.ToLower().ToCharArray()                      .Count(textSymbol => textSymbol == russianSymbol) // Считаем сколько раз буква встречается в тексте                     * (symbolPercentage); // Делим на длину текста                 inclusions = Math.Round(inclusions, 3); // Округляем до долей процента                 result.Add(russianSymbol, inclusions);             }              return result; // В результате: символы и их частоты         }      }

Я взял пять последних постов, пять первых, и посчитал медианы. Результат (Буква-Ранний Милфгард-Поздний Милфгард):

а 0.0864 0.09
б 0.0148 0.0172
в 0.043 0.0388
г 0.0164 0.0166
д 0.0294 0.0292
ъ 0 0
ы 0.0228 0.0204
ь 0.0176 0.0186
э 0.0038 0.0042
ю 0.0064 0.0058
я 0.0186 0.018

Как видно, отличие есть. Сравнивать, очевидно, надо с последними постами, я же провожаю 2016 год. Сравнить надо быстро: через два часа за стол. Поэтому среднеквадратичное отклонение от медианы Милфгарда не катит. Вместо этого я дополнительно беру медиану от постов Alizar, и сравниваю свою медиану с Милфгардовой и Ализаровой.

int result = 0;              foreach (var stat in stats)             {                 double MilfgardDiff = Math.Abs(stat.NewMilfgard - stat.Oxoron); // Сравниваю медианы: мою и Milfgard                 double AlizarDiff = Math.Abs(stat.Alizar - stat.Oxoron); // Сравниваю медианы: мою и Alizar                 char res = MilfgardDiff > AlizarDiff ? 'M'                                                                    : Math.Abs(MilfgardDiff - AlizarDiff) < 0.0001 ? 'N'                                                                    : 'A';                 if (res == 'M') result++;  // Ближе к Milfgard                 if (res == 'A') result--; // Ближе к Alizar                         }              Console.WriteLine();             Console.WriteLine(result < 0 ? $"{-result} ALizar" : $"{result} Milfgard"); // Результат. Для меня - 8 Alizar 

Как видим, полученный метод оценки прост и универсален. Область его применения чрезвычайно широка: можно сравнивать свое сходство с джавистами и шарпистами, рубистами и пхпешниками, эфШарпистами и хаскелистами. Также можно определить какой фреймворк JS лучше всего подходит вашей личности. Но какой бы результат не вышел — стремитесь к новым вершинам, коллеги, чтобы другие люди сравнивали себя с вами. С праздником!

P. S. Milfgard и Alizar выбраны исключительно для демонстрации работы метода, как одни из самых примечательных авторов хабры.
ссылка на оригинал статьи https://habrahabr.ru/post/318864/

Добыча полезных ископаемых на астероидах: кто и почему собирается этим заниматься

image

Полезные ископаемые жизненно необходимы для современной цивилизации. Мы используем все больше ресурсов, и вскоре, как предполагают многие ученые, ряда ресурсов может оказаться недостаточно для продолжения развития в текущем темпе. Металлургия, автомобилестроение, производство электроники, научная сфера, аэрокосмическая промышленность и многое другое зависит от полезных ископаемых. Предвидя грядущий дефицит, специалисты уже давно говорят о том, что добывать ископаемые нужно в космосе — на других планетах и астероидах. Насколько можно судить, астероиды являются действительно перспективным источником нужных человеку химических элементов и их соединений.

Максимальный интерес пока что вызывают два типа астероидов — водные и металлические (или же каменно-металлические). Что касается первых, то они содержат большое количество воды. Доставлять воду на Землю пока нет смысла, но вот если у человека появятся колонии на Луне, Марсе или других планетах и планетоидах, тогда такие астероиды можно отправлять к колониям. Одного водного астероида хватит на многие годы снабжения космической колонии. Кстати, это наиболее распространенный вид астероидов — их в Солнечной системе около 75%.

Почему астероиды — это хорошо

В металлических или каменно-металлических астероидах много таких металлов, как железо, никель и кобальт. Конечно, есть и другие элементы, которые могут пригодиться человеку: золото, платина, родий, редкоземельные металлы. Они могут быть полезными не только для колонистов, но и для промышленности Земли.

Перспективными для разработки астероидами являются те из них, которые можно приблизить к Земле с минимальными затратами энергии. Подобные астероиды ученые предлагают переводить к одной из орбит рядом с точками Лагранжа L1 и L2, где их можно оставлять в относительной неподвижности. Обе орбиты удалены от Земли примерно на миллион километров.

НАСА, согласно своей программе, о которой рассказывалось выше, собирается выбрать небольшой астероид (всего около 7-10 метров в диаметре), который расположен неподалеку от Земли, и перенаправить его к Луне. Есть и альтернативный план — разделить более крупный астероид на две части, и отправить часть, меньшую по размеру, к Луне. Стоит отметить, что программа будет не такой уж и дорогой. То есть сумма будет солидной — это 1,25-2,6 млрд долларов США, но все же подъемная даже для отдельно взятой организации. Астероид планируется изучать, чтобы получить информацию о его происхождении и свойствах. На примере одного объекта можно будет отработать схему перенаправления и других космических объектов. НАСА занято выбором одного из трех астероидов для отправки беспилотной миссии.

На данный момент в Солнечной системе обнаружены сотни тысяч астероидов, в каталоге их содержится уже около 700 тысяч. Орбиты большей части (почти полумиллиона) определены с удовлетворительной точностью, а сами астероиды получили официальный каталожный номер. Около 20 000 небесных тел имеют официально утвержденные наименования. Эксперты утверждают, что в Солнечной системе, скорее всего, находится от 1,1 до 1,9 миллиона объектов, размер которых превышает 1 км. Больше всего астероидов, конечно, в поясе астероидов, который расположен между орбитами Юпитера и Марса. Эту область также часто называют главным поясом астероидов или просто главным поясом, подчёркивая тем самым её отличие от других подобных областей скопления малых планет, таких как пояс Койпера за орбитой Нептуна, а также скопления объектов рассеянного диска и облака Оорта.

Досягаемыми для человека являются те из астероидов, орбиты которых находятся в пространстве между Марсом и Луной. Если туда можно отправить космический корабль (с минимальными затратами), то, скорее всего, такой астероид можно разрабатывать. Пока что ученые насчитали около 12 000 доступных для человека астероидов — а это уже солидная цифра.

Не так давно шотландские ученые попытались оценить перспективность добычи полезных ископаемых на ряде объектов, близких к нам. В расчет брались затраты энергии, расстояние до объекта, возможность изменения орбиты астероида и ряд других факторов. На основе этого были выбраны 12 разных астероидов, которые, по мнению шотландцев, можно начать разрабатывать уже сейчас или же в ближайшем будущем.

Кто и как будет добывать?

Различные способы разработки предлагают несколько компаний и организаций, включая НАСА. Агентство еще в 2013 году начало реализацию проекта по доставке небесных тел в окрестности Земли (Asteroid Retrieval Mission). В рамках проекта к астероиду (это пилотный проект, поэтому работать предполагается с единственным объектом) предлагается отправить автоматическую станцию, которая сможет захватить объект при помощи специального приспособления. После захвата астероид планируют доставить на орбиту Луны для дальнейшего изучения. Астронавты НАСА даже проходят тренировку в центре имени Линдона Джонсона, отрабатывая приемы по выходу из капсулы Orion в прототипах «астероидных скафандров» и добыче образцов пород астероида.

Кроме того, различные способы ведения разработки полезных ископаемых на астероидах предлагает и частная компания Planetary Resources, созданная при участии Джеймса Кемерона и Ларри Пейджа. Цель этой компании — разработка технологии, позволяющей добывать полезные ископаемые на астероидах. Аналогичную деятельность ведет и компания Deep Space Industries. Ее основатель — Рик Тамлинсон.

Программа США

Конгресс США активно работает по вопросу добычи полезных ископаемых в космосе, разрабатывая закон, открывающий возможность американским компаний добывать ресурсы на астероидах. Закон называется Space Resource Exploration and Utilization Act of 2015, говорится следующее: «любые ресурсы, добытые на астероиде в космосе, являются собственностью лица или организации, которые получили эти ресурсы, все права принадлежат добытчикам».

Закон разрабатывается Конгрессом для того, чтобы защитить интересы американских компаний. Здесь, как уже писалось ранее, есть большая проблема. А именно — соглашение от 1967 года, согласно которому все, что добывается в космосе, принадлежит всем нациям. Это соглашение носит название «Outer Space Treaty» и в США у него много сторонников. Тем не менее, в ходе дебатов конгрессмены предложили считать, что это соглашение, на самом деле, вовсе не закон, а просто полуофициальный документ, у которого нет юридической силы. В 67-м году вряд ли кто-то думал, что разработка астероидов начнется в скором времени, поэтому сам документ был составлен в качестве красивого жеста. Сейчас же эта сфера уже не просто пища для размышлений для писателей фантастов, но и предмет интереса коммерческих организаций и правительств ряда стран.

Люксембург впереди планеты всей

США действуют достаточно активно в плане развитие своей «астероидной» компании, но есть еще одна страна, которая работает в этом направлении не менее энергично. Речь идет о Люксембурге. В этом году Министерство экономики страны начало создавать законодательную базу, позволяющую начать разработку астероидов — добычу как минералов, так и различных металлов. Причем, в отличие от программы США, принять участие в этой программе может любая компания, у которой есть в Люксембурге свое представительство.

Согласно законодательству, компании, которые планируют заняться разработкой околоземных объектов, получают право на добытые ресурсы. Люксембург же будет лишь выдавать лицензии и вести мониторинг добывающих компаний.

Почему Люксембург? Ведь эту страну сложно разглядеть даже на относительно масштабной карте Европы, не говоря уже о карте мира. Люксембург никогда не отправлял космические корабли на орбиту, своего космодрома здесь нет, космической программы — тоже. Население же Великого Герцогства составляет всего 500 тысяч человек. И тем не менее, правительство страны считает, что добыча ископаемых на астероидах — перспективное занятие.

Много лет в Люксембурге добывали железную руду, в но в 70-е годы прошлого века эта сфера пострадала от кризиса и правительство приняло решение диверсифицировать как промышленность, так и экономическую сферу. Своей космической программы здесь нет, да, но зато в Люксембурге, например, работает компания SES, чья сфера деятельности — спутники. Она была основана еще в 1985 году. Эта компания является одним из крупнейших операторов спутников в мире. Сейчас SES управляет полусотней спутников на орбите. Кроме этой компании в Люксембурге действуют и другие.

Planetary Resources, упомянутая выше — одна из таких компаний. В ноябре она инвестировала около $26 млн в экономику Люксембурга «Я уверен, что Люксембург, как никакая другая страна в мире, возлагает надежды на коммерческую разработку астероидов», — говорит СЕО Planetar Resources Крис Левицки (Chris Lewicki). «Они (правительство страны, — прим. ред.) предпринимают ряд шагов, включая разработку законодательной базы, которая помогает создать необходимую среду для бизнеса, планирующего участвовать в разработке астероидов». Planetary Resources разработала спутник, Arkyd 6, который предназначен для обнаружения воды на астероидах. Запустить этот спутник планируется весной 2017 года. После этого компания планирует начать уже полноценную разработку, к 2020 году.

Программа по разработке астероидов создается при участии экспертов по праву, ученых, астронавтов и руководителей космических программ разных стран и организаций. По плану, предложенном правительством Люксембурга, новое законодательство должно вступить в силу уже в 2017 году.

Преимущества и недостатки добычи полезных ископаемых на астероидах

Выше упоминались как преимущества, так и недостатки ведения разработки астероидов. К преимуществам можно отнести такие моменты, как:

  • Близость к Земле — некоторые астероиды находятся к нам достаточно близко, так что отправка пилотируемой или автоматической миссии к этим объектам не является неподъемной для человека задачей;
  • Уже сейчас эксперты выделяют тысячи и тысячи перспективных объектов, с течением времени их количество будет только увеличиваться, по мере изучения учеными;
  • В астероидах может быть большое количество полезных ископаемых, включая железо и редкие на Земле элементы;
  • Астероиды могут быть полезным ресурсом как для колонистов будущих колоний на Луне или Марсе, так и для землян.

К недостаткам же можно отнести такие моменты, как:

  • Низкая гравитация на астероидах — людям, которые будут работать в качестве «космических шахтеров» придется непросто;
  • Большая часть перспективных астероидов находятся далеко от Земли, и поступление солнечной энергии на большинстве в несколько раз меньше, нежели на Земле, так что и солнечных элементов нужно больше;
  • Большое количество астероидов могут оказаться бесполезными для человека;
  • Астероид может столкнуться с себе подобным небесным телом.

Как бы там ни было, но прямо сейчас разрабатывать астероиды готовятся как коммерческие, так и государственные организации. Это позволяет говорить о том, что раз уж эксперты, ученые и предприниматели считают добычу полезных ископаемых на астероидах перспективным делом, то, вероятно, это так и есть.
ссылка на оригинал статьи https://geektimes.ru/post/284240/

Построение мобильных приложений с Ember

Быстрый способ построить быстрое приложение

Существует страх у разработчиков, что быстрые решения — это проблема. Откуда происходят опасения — в отсутствии возможности масштабирования своего приложения в будущем. Ведь для этого нужно продумать архитектуру! А что если её продумали за вас. Вы же не пытаетесь изобретать велосипед?

Быстро и масштабируемо — так позиционирует себя экосистема Ember. Фреймворк на JavaScript c понятной современной и расширяемой архитектурой, способный в считанные минуты создать рабочий каркас не только для большого многофункционального сайта, но и для десктопного приложения, используя популярный нынче Electron.

И вот ведь неугомонно-амбициозный — замахнулся аж даже на нашего, так сказать, мобильного младшего брата. Что из этого вышло — давайте взглянем.

Стек используемых технологий

Не вдаваясь в подробности обоснования выбора, пусть для начала это выглядит так:

  • Ember.js
  • Cordova
  • Handlebars
  • CSS (no S(A/C)SS)
  • HTML
  • JavaScript

Почему Ember

Почему бы просто не взять Cordova и сделать то, что нам нужно? Да, но нам нужна масштабируемость и ремонтопригодность нашего приложения, которую за нас уже продумали! И да, нам желательно иметь уже готовую архитектуру.

Создание вашего проекта

Для начала нам нужно убедиться в присутствии нужных библиотек и правильной настройки рабочей среды.

Установим нужные пакеты:

npm install -g ember-cli npm install -g cordova

Теперь вы готовы создать свой проект:

ember new my_freaking_awesome_app

Ember.js + Cordova

Одной из ключевых проблем разных фреймворков является тот факт, что приходится постоянно что-то к чему-то как-то прикручивать. В нашем случае всё опять же таки продумали за нас. Остаётся установить нужную «прикрутку»:

ember install ember-cli-cordova

Запустим встроенный генератор:

ember generate cordova-init com.my_company.my_freaking_awesome_app

Данный генератор позволяет создать идентификатор нашего мобильного приложения — com.my_company.my_freaking_awesome_app.

Указать целевую платформу iOS или Android — мы сможем позже через Cordova.

Пробный запуск

Наш каркас проекта создан и мы можем посмотреть как оно выглядит:

ember serve

Запустите данную команду из командной строки в папке проекта и откройте браузер по адресу localhost:4200.

Пока это пустой проект, но легко масштабируемый с готовой продуманной архитектурой. И да, со встроенными тестами. Да-да, тестировать с Ember легко и весело.

Этим мы и займёмся в следующих статьях.

Спасибо João Moura за идею и доступное объяснение.
ссылка на оригинал статьи https://habrahabr.ru/post/318862/

«Меня разрывает, когда я не могу писать код» — интервью с Максимом Шафировым, CEO JetBrains

В новогоднем выпуске «Без слайдов» — Максим shafirov Шафиров, CEO компании JetBrains.

Вот о чем мы поговорили с Максимом:

  • Важен ли для JetBrains российский рынок?
  • Почему Максим не прекращает писать код?
  • Насколько помогает догфудинг и в чём его ограничения?
  • Почему компания редко закрывает продукты?
  • Как появился Kotlin, и какими компания видит его перспективы?
  • Почему компания не была продана, несмотря на щедрые предложения?
  • Как в JetBrains появилась должность PMM?
  • Как JetBrains одновременно конкурируют и сотрудничают с Microsoft?

Как обычно, под катом — полная текстовая расшифровка беседы.

О работе на российском рынке

— Начну с цитаты из интервью РБК, которое ты давал этим летом. Кстати, называлась статья очень интересно: «Как построить глобальный бизнес на эмпатии».

— Как ты, конечно, понимаешь, название придумал не я. Журналисту главное — придумать название…

— Ну, на самом деле, это довольно близко к тому, что про вас говорят: вы сами кастомеры собственных продуктов, и эмпатия, наверное, правильное слово. Мне понравился заголовок. А цитата такая. Журналист делает вводную о том, что российский рынок является для JetBrains периферийным, и ты говоришь следующее: «Сейчас ситуация несколько изменилась — мы открыли российское отделение продаж, чтобы отечественные покупатели могли не отправлять деньги в Чехию, как происходило раньше, а платить внутри страны. Так что сейчас я подписываю все эти бумаги. И вот, судя по объему бумаг, на российском рынке дела тоже идут неплохо — заказы есть, их становится больше».

Каждый раз, когда я разговариваю на мероприятиях вроде JavaOne с ребятами, которые заняты разработкой продуктов, они говорят одно и то же: «Россия для нас — не рынок». Потому что мало продаж, люди не привыкли платить за софт, и ещё ряд известных причин.

Для JetBrains Россия — рынок или не рынок?

— Ну, настолько же, насколько российский рынок софта является частью мирового. Все знают, что самый большой рынок софта — это Штаты (если не считать Китай, где сейчас специфическая ситуация). Потом идёт Европа, потом все остальные. Россия занимает где-то один-два процента. Ну и вот эти 1-2% в нашей структуре продаж точно так же фигурируют. Рынок это или не рынок? Да, рынок, и хороший.

— Влияет ли [на вас] как-то тот факт, что большинство ваших разработчиков находятся в России и компания корнями отсюда, на продажи, маркетинг?

— Никак не влияет.

— Несмотря на то, что есть каналы типа Хабра, и много людей в тусовке, все всех знают?

— Скажем так, я не знаю способа корректно измерить это влияние, но мне кажется, что оно не особо чувствуется. Нам приятно, что нас знают, это помогает нам как HR-бренду нанимать хороших людей, потому что они знают, что будут делать: то, чем сами пользуются в своей работе каждый день. Это польза. А с точки зрения денег — не знаю.

— Но всё равно рынок растёт? Рука не устала бумаги подписывать?

— Устала. Мы пытаемся внедрить какие-нибудь системы (оказывается, российские производители тоже такие делают), где можно подписывать документы электронным образом.

— А есть какие-то истории с интеграторами, людьми, которые это продают? Вот Microsoft в России продаётся через партнёров.

— Да, конечно, есть, но мы совершенно не отслеживаем, кому они продают, никак не участвуем в работе с конечными клиентами. Без этого у нас вообще не было бы никаких корпоративных продаж в России, потому что чисто технически обосновать передачу денег за границу для многих компаний трудно.

— Да, есть валютный контроль, НДС, целая история…

— Но это не чисто российская история. Такие реселлеры, чтобы чисто деньги собрать, есть во многих странах мира.

— Вы будете что-то с Россией специально делать, или воспринимаете рынок таким, какой он есть?

— Он хороший, нам нравится. Зачем с ним что-то специальное делать? Я думаю, что продуктовые российские компании к нам так или иначе все приходят, мы их знаем, вы их знаете. Можно назвать имена, но это ничего не расскажет дополнительного. Есть такой специальный сектор, как государственные компании или просто государственные структуры, вот с ними можно было бы как-то специально работать, но у нас тут случился казус, и теперь им нельзя покупать наш софт!

— То есть для них вы не российская компания?

— Для них мы не российская компания, потому что интеллектуальная собственность принадлежит чешской компании. У нас так устроен бизнес, что чешская компания заказывает разработку российской, российская делает на заказ за денежку, интеллектуальная собственность остаётся на балансе у чешской. Когда вы покупаете что-то, вы покупаете это у чешской компании. А [для продаж госкомпаниям] нужно быть в специальном реестре. И если в этом реестре есть хоть что-нибудь, отдалённо напоминающее конкурента по названию или по рубрике, то вы не можете купить зарубежный продукт, вы должны купить российский.

— Так а ведь нет же никого!

— Фактически нет, а если почитать реестр — то есть.

— Есть IBM с Eclipse, есть Oracle с NetBeans — и они же все тоже иностранные.

— Ты перечисляешь реальные конкурентные альтернативы, а есть бумажные конкурентные альтернативы.

— Это довольно забавно. То есть это всё с импортозамещением связано, с такими вещами?

— Ну, нас это не особо печалит, потому что с точки зрения денег, там их и не было. Нас печалит, что пользователи, которые хотели бы что-то купить у нас, не могут этого сделать, пишут нам «давайте вы внесётесь в этот список, Касперский же внёсся каким-то образом». А мы не можем им помочь. Обидно.

О совмещении разработки и управления

— У вас есть ещё линейка серверных продуктов.

— Да.

— Довольно большая, и если я правильно понимаю, когда у вас было два СЕО, Олег Степанов больше занимался ими. В связи с чем у вас было такое разделение?

— Ну, просто функционально сложилось. Не то что мы делили сферы ответственности, но я занялся инфраструктурой продаж в тот момент и был крепко занят этим, а Олег занялся чем-то другим.

— А что такое инфраструктура продаж?

— Это система, в которой идёт учёт всех лицензий, в которой карточки, ремайндеры, оплаты…

— А почему вы не взяли готовое решение? Наверняка много таких решений есть на рынке.

— Все решения на рынке тебя загоняют в какую-то канву. У нас исторически сложилось так, что наша идея лицензирования софта — нестандартная. Кроме того, когда нам пришло в голову, что надо бы навести порядок, у нас уже было довольно много клиентов, так что выкинуть историю и начать с нуля мы не могли себе позволить. Наверное, мы могли ее кому-то заказать. Мы даже посмотрели на какие-то варианты ERP-систем типа SAP и NetSuite — и это страшно, туда вкладываться страшно.

В некоторых подразделениях, в частности, в пражском, мы стандартизовали NetSuite, потому что там банально не было бухгалтерии in-house, она была на аутсорсе. И это был чрезвычайно мучительный процесс, так что хорошо, что мы не перевели на NetSuite систему обслуживания клиентов.

— У вас есть важное преимущество: вы люди, которые разрабатывают софт!

— Да.

— Ты сам до сих пор тоже занимаешься разработкой?

— Да.

— Расскажи, тебя вообще не разрывает от этого, когда у тебя и «код писать», и «за компанию отвечать»?

— Меня разрывает, когда я не могу писать код. Это, может быть, высокопарно или банально прозвучит, но если я за день не написал ни строчки кода, я чувствую себя очень плохо, я чувствую некоторое неудовлетворение. Несмотря на то, что я решал жутко важные вопросы, где-то кому-то с чем-то помогал или какие-то разговоры вёл, всё-таки для меня важно что-то написать, чтобы что-то работало.

— А ты думал в ключе «для бизнеса важно, чтобы я уделял больше внимания бизнесу, а код за меня напишет кто-то другой, у нас много умных ребят»?

— Да, думал. А потом придумал вот эту отмазу с эмпатией, и мне стало очень хорошо! Мне нужно понимать, как работает бизнес, зачем он работает, для кого он работает. И сейчас я его понимаю и с той, и с другой стороны.

О догфудинге

— Очень здорово — начинать историю на эмпатии, на догфудинге. Но в какой-то момент ты вычищаешь всю боль из продукта, и у тебя уже всё хорошо.

Если спросить у пользователя IDEA со стороны, что изменилось в IDEA за последние пять лет, тебе скажут — ну, появилась тема Darcula, ну, лямбды стали поддерживать. И у меня как у пользователя IDEA тоже нет ощущения, что она меняется. Вы же наверняка ведёте громадную работу — и перфоманс, и UI, и всё подряд, но это не чувствует пользователь. Вот как вы эту дихотомию для себя решаете?

— Надо в первую очередь признаться, что то, что «пользователь не видит» — это эффект восприятия, это ощущения пользователя. Потому что количество функциональности, которое мы делаем, зависит, как бы ни банально это прозвучало, от количества сил, которое мы туда вложили. Если у нас в начале над IDEA работало 3 человека, то за год появлялось 3 человекогода фич, а когда работает 90 человек, появляется 90 человеколет фич. Происходит накопление, и каждый следующий релиз отличается от предыдущего уже не в 10 раз, потом не в 2 раза, не в полтора, а, скажем, на 5%. А по объёму эти 5% — это даже больше изменений, чем происходило раньше.

В каждый конкретный момент времени каждому конкретному человеку понятно, как улучшить продукт. То, что это не всегда складывается в какую-то целостную картину, которую можно с точки зрения маркетинга подать пользователям — ну и бог с ним. Мы-то знаем, что продукт становится лучше. И в конечном итоге мы видим, что пользователи с нами согласны: деньги несут. Не были бы согласны — не несли бы.

— Всегда есть разрыв между тем, как воспринимает продукт инженер, который его делает, и как воспринимают его пользователи. Вы пытались выделить эту разницу, и если выделили, то что нарыли интересного?

— Постоянно пытаемся, и это мучительный процесс. Надо признать, что догфудинг — он несколько однобокий. То, что касается core-фич, работы с языком, каких-то generic-историй, рефакторингов, лампочек и инспекций — с ними всё понятно. Но с другой стороны, все люди, которые работают сейчас над проектом IDEA, пишут проект IDEA. Он стартовал 15 лет назад, он большой, специфический, в нём определённая структура модулей, и его не надо начинать с нуля. А когда к нам приходит какой-то новый разработчик, ставит продукт… В начале своей работы он понимает, что можно СТОЛЬКО улучшений сделать! Например, когда я сам из проекта IDEA вышел и попытался делать что-то сбоку, у меня волосы дыбом встали. Оказывается, всё не так шоколадно, как мне казалось!

Другое дело, что до команды эту историю нужно перманентно доносить. JetBrains не состоит из одной IDEA, он состоит из людей, которые разрабатывают и другие продукты. И в команду IDEA идёт поток информации не только от пользователей, но и от нас тоже, от «другого JetBrains». И подвижки есть, как мне кажется.

— У меня давно есть тезис, что догфудинг — это ловушка, в которую легко попасться. Он очень помогает на первых этапах, но начинает мешать потом. Но вот вы много лет используете догфудинг и при этом бешено растёте. Значит, мой тезис неверен? Видишь ли ты какую-то проблему в том, что у вас сплошной догфудинг? Если видишь, то как вы с этим боретесь?

Как вы, например, узнаете мнения о своих продуктах от людей снаружи? Я знаю, что у вас есть публичный багтрекер, но мы с тобой при этом понимаем, сколько людей пишут на Java, а сколько из них ходят в багтрекер IDEA. Очевидно, что это очень разное количество людей.

— Количество разное, но выборка статистически, я думаю, вполне репрезентативная.

— То есть в ваш багтрекер приходит много пользователей?

— Много. Это сотни тысяч человек, наверное.

— Ты писал систему, связанную с продажами — эта система отвечала только за продажи, или и какие-то маркетинговые вещи тоже, за трекинг каналов, например?

— Нет, тут мы использовали Marketo, пытались с ней интегрироваться. Мы пытались интегрироваться со всем, чем ни попадя.

— И как ощущения?

— Не очень. Если бы я делал продукт для маркетинга, наверное, я бы сделал что-нибудь более удобное.

— Мы (JUG.ru Group) тоже пытаемся отслеживать каналы — кто как о нас узнал, кто кому нас порекомендовал и так далее. Для нас это очень тяжёлая история, но мне кажется, что очень важная. Вы активно эту проблематику исследовали?

— Нет.

— У вас не было такой необходимости?

— Нет. Дело в том, что если компания-клиент маленькая, то она действительно с одного человека очень быстро, вирусно, подсаживается на наши продукты. Или нет. Это «работа снизу». А если компания большая, то необходима работа и сверху тоже. Не то что пытаться продавать кому-то — CTO или высшему менеджменту — но требуется работа сейлзов просто для обеспечения коммуникации. Какие-то скидки, личные взаимоотношения, помощь с апробацией, исследованием. Потому что люди в больших корпорациях вроде банков этого ждут, им это просто необходимо. Иначе ты для них выглядишь как какой-то мелкий вендор, который не отвечает за то, что он делает.

О пути в компании

— Ты же в JetBrains очень давно?

— 1 октября исполнилось 15 лет.

— Это с самого начала существовании компании?

— Почти с начала. Когда я пришёл, IDEA была версии 2.5.

— Каким ты был по счету сотрудником?

— Десятым.

— У тебя же были какие-то этапы: ты был инженером, потом продуктовым или проектным менеджером…

— Да, но я при этом всегда был инженером.

— А сейчас ты СЕО. А ты можешь какие-то этапы для компании выделить, которые как-то её меняли?

— В своём разрезе?

— Изнутри — раз, в разрезе рынка — два.

— Сейчас, вспомню все 15 лет… Когда я пришёл, у компании был один продукт — IDEA. И я лично начал с того, что я делал инспекции в IDEA, и начал я с самого простого, конечно — State Flow анализ, который подсказывает: «Вот эта область всегда true, а здесь вылетит NullPointerException». Сарказм в том, что это до сих пор наиболее продвинутая технология: инспекций мы написали полторы тысячи, но именно эта почему-то наиболее могучей оказалась.

— Ну, может быть, потому что NullPointerException — это «Billion Dollar Problem»?

— Не, его просто прикольнее всего было писать.

— Я к тому, почему до сих пор…

— Почему он полезный? Потому что он фундаментальный. Все остальные — они как шаблоны: «так не пишите, пишите вот так», и ещё пояснительная записка, почему так правильно, а эдак нет. А эта инспекция пытается понять структуру и семантику кода, которая напрямую в самом коде может быть не отражена, но вывести её оттуда можно. Я помню, первые полгода меня коллеги вызывали со словами «вот тут у тебя полная лажа», «вот этого не может быть», а я приходил и объяснял: «посмотри вот сюда, вот здесь условие такое-то, здесь вот это присвоится в это, а потом этот придёт отсюда, и вот тогда у тебя будет…» — «а, да, действительно!». Первые полгода мне никто не верил, но потом постепенно перестали ко мне ходить.

— То есть ты написал, на самом деле, кусок компилятора?

— Да, и даже чуть больше. Оно компилировалось действительно в некоторый псевдокод, и внутри ма-а-аленький интерпретатор а-ля виртуальная машина, который пытается разобрать все неэквивалентные состояния памяти по control flow graph’у, а потом, соответственно, посмотреть их на совместность и выделить какие-то условия, которые могут быть интерпретированы как баги.

Потом Сергей Дмитриев, основатель, довольно много чего написавший, написал первую версию редактора.

— То есть изначально это был не редактор, а какой-то отдельный инспекшен? Как это работало?

— Не-не, ты запутался. Кроме inspections, я начал поддерживать редактор.

— Ты конкретно?

— Да, конкретно я. Исправил там миллион проблем, просидел с профайлером в первый раз в жизни, на Pentium III, я специально попросил себе машинку, которая…

— … не тормозила?

— Нет, наоборот, которая тормозила! Потому что пользователи жаловались нам: «У вас лаги и код печатать невозможно!», а я на Pentium 4 не мог этого увидеть.

— Это тоже догфудинг, только в другом разрезе.

— Запустил первый профилировщик в своей жизни, и он СКРИПЕЛ. Это было так: ты нажимаешь клавишу, чтобы проверить скорость того, как это печатается, и можно было через десять минут подойти и получить трейс того, что происходило в это время, а потом как-то пытаться это оптимизировать.

Занимался в редакторе фолдингом, перфомансом, исправил кучу багов, сделал кучу фич. А потом пришёл Сергей Дмитриев (основатель и президент JetBrains — прим. авт.) и сказал: «Давай ты будешь руководить IDEA». Вот в такой постановке вопроса. Я говорю: «Вы чё, офигели, что ли?»… Ну ладно, говорю: «Как же так?».

Потом дня три походил с «Как же так?» в голове, и решил, что надо попробовать. И попробовал. Собрал кучу шишек. Когда говорят, что из программистов получаются плохие менеджеры — это, конечно, в определённом смысле правда. Все те же шишки, которые какой-то менеджер уже где-то собрал, тебе придётся собрать заново.

О том, как закрываются некоторые проекты

Ладно, я же про компанию рассказываю, да? Ну вот, к тому времени у нас уже был проект Fabrique, который оказался закрыт. Это была идея «давайте мы сделаем такой мега-инструмент для написания веб-приложений, там будет какой-то серверный движок, чтобы UI можно было рисовать на картинке, AJAX там поддержим, WYSIWYG».

— Это была середина двухтысячных?

— Да, слово AJAX только начало появляться, ещё не вошло в мейнстрим, это был, наверное, 2004-й год. Так вот, проект Fabrique был закрыт за десять дней до своего первого релиза.

— Не полетело?

— Пришло осознание, что не полетит.

— А как вообще принимаются решения о закрытии? Вы же вложили очень много сил в этот проект? И это же наверняка не единственный проект, который вы закрыли?

— Мы очень мало что закрывали. Положа руку на сердце — наверное, можно было бы закрыть больше. Но легко закрывать проект, пока ты не выкатил его пользователям. Потому что после того, как ты его выкатил, даже если у тебя нет никаких прямых обязательств (вроде тех, что они заплатили тебе денег или рассчитывают на багфиксы, сопровождение), всё равно есть коммитмент. Закрытие зарелизенного проекта негативно влияет на то, как люди воспринимают твою компанию.

Компания Google, наверное, может позволить себе закрывать проекты направо и налево просто потому, что может. Сколько было шума про закрытие Reader? Им пользовались миллионы человек! Компания Google осознала, что не может себе позволить сопровождать такой проект, просто некому внутри этим заниматься, никто не хочет. Они могут закрыть даже то, про что сами раньше с фанфарами трубили: «Wave — это новый способ коммуникации, e-mail-киллер, вы сейчас все будете писать в Wave»… Пробуешь — действительно красиво. Но не пошло. Взяли и закрыли.

У нас не так. Мы закрыли Fabrique, мы закрыли OmniaMea — это был такой написанный на .NET информационный аггрегатор: ридер имейла, ньюзгруп, RSS-фидов, отслеживание контента сайтов… Если нужно отслеживать какой-то большой объём информации, есть коробочка, которой это удобно делать. И там была куча смарт-фич. Как бизнес это не полетело, и приняли решение закрыть. И это чуть ли не всё из закрытий продуктов.

— Получается, что как только ты свой продукт кому-то продал, для тебя это сразу легаси. Есть то, что у тебя растёт, а есть то, от чего не можешь отказаться, потому что у этого чего-то есть кастомеры. Есть ли сейчас проекты, которые тянут вас вниз?

— Я бы не хотел это комментировать. Скажем так: есть проекты, которые приносят меньше денег, чем мы на них тратим.

— Понятно. Портфель для того и нужен, чтобы диверсифицировать. Была ли в своё время история с запуском ReSharper попыткой диверсифицировать ваш бизнес?

— Да, конечно, абсолютно.

— А что вас тогда напугало? IBM и Eclipse? Расскажи чуть-чуть про это, что вы тогда чувствовали?

— А я тогда был инженером. Это довольно забавно для меня, сейчас ретроспективно я понимаю, что когда Сергей Дмитриев сказал «а давай ты будешь руководить IDEA», он на самом деле имел в виду, что IDEA конец, потому что Eclipse её сейчас убьёт. И не важно, кто будет этот проект дальше развивать, но нужно, чтобы какое-то время проект побыл на плаву…

— Потому что есть кастомеры…

— Да. Ну и может, ещё побарахтаемся…

— Как интересно.

— Ну, может, он и не признается сейчас в этом, но я как-то так это сейчас вижу. Ну и действительно была такая ситуация: все действительно либо закрылись, либо переписали свои IDE на базе Eclipse — Borland Together, например.

И возвращаясь к твоему вопросу о том, что «мы во всём правы и догфудинг очевидно хороший способ, потому что мы хорошо зарабатываем» — нам еще конкуренты помогают, и это тоже довольно существенно.

— Что ты имеешь в виду?

— Ну, я наблюдаю, что у Eclipse сейчас дела идут не очень хорошо.

— То есть вы учитесь на их ошибках, или просто они сами себе могилу роют?

— Роют, причем откровенно: их пользователи жалуются на качество. Они и раньше жаловались, но была какая-то динамика развития. А сейчас — есть сайты, где можно посмотреть, сколько в Eclipse коммитов делается (IDEA Community и Eclipse — опенсорсные). И у нас, например, две сотни коммитов в день, а у них двадцать коммитов в месяц в такой же по функциональности code base.

— Есть ощущение, что они сдаются?

— Они не сдаются, конечно, просто у них нет финансирования. Это некоммерческая организация, которую финансируют разные большие корпорации.

— Это интересная история, потому что народ привык про опенсорс рассуждать как про какие-то некоммерческие вещи, но мы же отлично понимаем, что Java спонсируется Oracl-ом, Eclipse спонсируется IBM-ом и так далее — то есть, разработчики этих проектов работают не бесплатно.

— Бывают истории, когда люди работают бесплатно, но это не может продолжаться вечно.

— Это не про большие продукты. В то, что OpenSSL бесплатно делают три человека — я готов поверить. Но, например, в Linux контрибьютят сотрудники крупнейших вендоров, таких как Red Hat и Intel.

Почему я про это заговорил: мне очень нравится, что вы продаёте продукт за деньги. В России как-то не принято покупать. И, может быть, не только в России. Вообще эта история с опенсорсом и free software немножко пугает, потому что пользуются этими продуктами программисты, которые получают за свою работу деньги. Но вот платить за эти продукты их компании часто не готовы. Это чисто российское явление, или в остальном мире это тоже наблюдается?

— С одной стороны, в мире считается, что хорошо быть Open Source и плохо быть proprietary. С другой — в России есть ещё такая штука, что весь Software Development — это некоторое донкихотство. Нужно быть рыцарем в белых доспехах, делать хорошие вещи бесплатно, делиться им с миром. И в принципе зарабатывать в России много денег имеет некий флёр постыдности. Олигархи, «если у тебя хорошая машина — значит, ты наворовал»… К сожалению, есть такой шлейф. Это пройдёт, конечно.

— Но деньги помогают делать интересные вещи — например, создавать новый язык программирования.

— Не только. В первую очередь, деньги помогают делать то, что ты делаешь. Я абсолютно уверен, что пользователи наших продуктов заинтересованы в том, чтобы платить нам деньги. Потому что эти деньги будут использованы на то, чтобы сделать их инструменты лучше.

О Kotlin

— Я хочу поговорить про Kotlin. Я очень давно знаю Андрея Бреслава, он меня учил еще в школе, потом в институте — и я ему безумно за это благодарен. И в какой-то момент Андрей вернулся в Питер и сказал «я теперь делаю язык Kotlin в JetBrains». Кому и как вообще пришла в голову идея сделать свой язык программирования?

— Давай я всю историю расскажу. Пришёл Сергей Дмитриев и говорит: «Знаете, мне кажется, нам надо что-то интересное сделать. IDE, тулинг — это всё понятно, а что бы такого сделать, чтобы вывести компанию на новый уровень?» И Дима yole Жемеров ляпнул: «А давайте язык программирования сделаем!»

И Дмитриев пришёл ко мне: «Вот Жемеров говорит, давай язык программирования сделаем». А я отвечаю: «Господи, что за фигня? Где JetBrains, и где язык? Язык имеет смысл, только если он популярен. Вот IDE может захватить 5% рынка и отлично чувствовать себя на нём. А язык не может так, он имеет смысл, только если он мейнстрим». Я до сих пор так считаю.

— Ну, 5% для языка — это очень хорошо. По индексу TIOBE в районе 5% заканчивается первая десятка (на самом деле — тройка — прим. авт.).

— Хорошо, 5% — это я загнул. И мне в какой-то момент казалось «ну нет, это невозможно просто потому что невозможно». А потом я подумал: вот мы поддерживаем языков 20 или 30, я уже даже сбился со счёта. Всяких разных. И мы знаем, как люди на них пишут. Мы знаем, где в каждом языке разложены грабли, знаем все их плюсы и минусы — не только с точки зрения каких-то формальных фич и чекбоксов, а с точки зрения практического использования всех этих языков.

— То есть вы накопили экспертизу.

— Да. И пришло понимание, что, наверное, JetBrains — самая технологически подкованная компания для того, чтобы сделать язык программирования, который будет действительно использоваться в индустрии. Потом мы провели все эти стандартные разговоры, «почему не Groovy?», «почему не Scala?», «почему не что-нибудь еще?» И мы начали думать, какой это будет язык. Мы были абсолютно уверены, что нужна статическая типизация, потому что статическая типизация — это тулинг, а тулинг — это IDE, а IDE — это деньги, ну и вообще — это удобнее и быстрее. Мы накидали какой-то список фич, а потом Андрей Иванов привёл Бреслава, и тот начал нас спрашивать.

И это был Jam Session. Я его отлично помню от первой до последней минуты. Он начал задавать вопросы, я отвечал на них — почему не Scala, почему не Groovy, все те самые. Он довольно скептически был настроен, но, тем не менее, открыт к диалогу.

И к концу разговора, часа, наверное, через четыре, у нас уже было чёткое понимание, что Андрей у нас работает, и делает он вот это и вот это. Потом он уехал в Microsoft Research на год, делал там какое-то исследование, потом он вернулся, и мы с ним где-то полтора года сидели в комнате и просто дизайнили новый язык.

— То есть сначала вы это вдвоём делали? В четыре руки, в две головы?

— Ну, это слишком нескромно. Участвовали другие люди, конечно. Всякие идеи обрабатывались и апробировались в коридоре. Очень много ребят (тот же Дима Жемеров, тот же Илья Рыженков, Володя Решетников, который сейчас в Microsoft), высказывали массу идей, комментировали. Или Рома Елизаров — он пришёл к нам, потому что я позвал: «Ром, я буду в JetBrains рассказывать, как мы будем делать язык программирования, приходи».

— Какой это был год?

— 2011-й. Может, 2012-й. Рома пришёл, послушал, сказал: «Чуваки, всё классно… Но Nullability». И мы такие: «Ну это трудно: дженерики, interoperability с Java»… Он: «Nullability, чуваки». И появилось Nullability.

— Это очень интересно, потому что Рома Елизаров зимой тоже был в «Без слайдов», и тогда он ещё был сотрудником компании Devexperts, а теперь он сотрудник компании JetBrains и внезапно он делает Kotlin Native, о котором мы ещё поговорим. То есть он ещё тогда, на том этапе, был человеком, который существенно повлиял на язык?

— Да, именно Рома предложил конкретно Nullability. И это сейчас, наверное, одна из самых главных фич в Котлине — это понятная вещь, удобно объяснять пользователю. Но Рома дал идею, а нам пришлось действительно сильно пыхтеть для того, чтобы сделать её реализацию в языке удобной, потому что Nullability в типовой системе… Если её наложить на Java, этим невозможно будет пользоваться. Нужны ещё какие-то механизмы в языке: вопросики, точки…

— Я видел, Андрей рассказывал: один восклицательный знак, два восклицательных знака, вопросительный знак…

— Всё это довольно итеративно появлялось.

— Когда вы это запускали, у вас был прогноз «тогда-то мы выпустим язык»?

— Да. У нас был прогноз, что мы выпустим язык через полтора года. Потому что «чё там делать — надо всего лишь написать компилятор».

— А релиз состоялся, как я понимаю, этой весной?

— Лет через пять после той даты, когда мы сказали, что будет через полтора года.

— Пять лет: сначала два, потом пять, сейчас уже чуть ли не тридцать или даже больше, делают новый язык программирования. Это огромное количество сил, нервов и, конечно, денег. То есть, скорее всего, каждый год на этот проект компания тратит миллионы долларов. Как вы вообще оцениваете эту инвестицию с точки зрения бизнеса?

— Как стратегическую.

— То есть вы делаете серьёзную ставку на Kotlin?

— Да, абсолютно. Когда Kotlin станет мейнстрим-языком, значение компании JetBrains для рынка Software Engineering, на котором она работает, будет совершенно другим. То есть, про нас будут говорить, что мы не какие-то ребята, которые делают удобные, но в любой момент заменяемые инструменты, а как про тех, кто делает некоторую корневую фичу экосистемы, на которой всё строится. Это другой вес, другой информационный поток, и деньги, я думаю, тоже другие.

— На момент интервью в РБК ты называл годовой оборот, по-моему, в 147 миллионов долларов. Это большие деньги. Вы инвестируете вообще в другие проекты, кроме Kotlin? Вот языки вы уже все съели, только IDE для Go, наверное, нет. (интервью было взято до анонса Gogland — прим. авт.)

— Будет!

— Отлично, теперь все узнали, что таки-будет. Есть язык Go, есть JetBrains…

— «Вы привлекательны, я чертовски привлекателен, чего зря время терять»…

О серверных тулах

— С этой историей мне всё понятно. А вот что дальше? Позволяет ли вам ваш нынешний объём инвестировать в разные проекты исследовательские, может быть, в другие компании?

— Смотри. С точки зрения JetBrains мы для себя определили на ближайшие сколько-то лет, что JetBrains всё-таки занимается Software Development. Всё-таки наш клиент — это программист или команда программистов, и мы будем делать продукт, который сфокусирован на этой группе. Конечно, это не только IDE.

В частности, ты говорил про серверные тулы — на мой взгляд, сейчас у нас в них не полная картинка. У нас есть тулы, которые закрывают какие-то конкретные фичи, а других конкретных фич не хватает. Это какое-то кусочное вырезание, аппликация из общего одеяла. А нам бы хотелось сделать инструмент, который является для команды настолько же интегрированной средой, насколько IDE является средой для программиста.

И анекдот заключается в том, что когда мы начинали, например, TeamCity, наш первый серверный продукт, у нас была ровно такая мысль. Мы сказали: «Вот, ребята, мы сделали IDE, можно сказать, что она готова— в принципе уже в 2005-м от IDE ничего больше было не надо.

Инкрементальные улучшения, конечно, имеют большой эффект кумулятивно, но, тем не менее, это инкрементальные улучшения. И вот мы думаем: окей, давайте мы сделаем Integrated Team Environment, но с чего-то нужно начать, с какой-то конкретной истории. Тогда для Continuous Integration, был CruiseControl — это такая система, которая хранится на одной машинке, которую нужно конфигурировать xml-ным файлом. И если у тебя, например, два проекта, нужны две машинки, если билд идёт долго, то опять же нужны две машинки, их надо отдельно настраивать, никакой интегрированной истории, в общем, трэш и угар.

— Но в то время Косукэ Кавагути уже работал над Hudson, который сейчас Jenkins.

— Тогда мы не знали про Hudson, знали только про CruiseControl, это был конец 2004-го. Так вот, что такое Integrated Team Environment, было еще непонятно, и мы решили сделать понятную конкретную вещь: Continuous Integration. Сделали, по-моему, за год или полтора, выпустили, пришли пользователи, сказали «не хватает вот этого и этого», мы сделали это и это, выкатили пользователям, они сказали «нам теперь ещё вот здесь подмазать, здесь подкрасить, здесь ещё вот эту version control system интегрировать», ну и мы, что называется, увлеклись.

Этот процесс напоминает следующее: человек начинает копать ямку под дерево, а потом случайно выкапывает траншею, и по сторонам уже ничего не видно. Единственное, что он может делать — эту траншею углублять. И так же у нас получился YouTrack, так же получился UpSource (code review-тул), и сейчас мы в очередной раз пытаемся переосмыслить «а что такое вообще командный инструмент, как он должен быть устроен».

— С TeamCity я примерно понимаю, всё-таки сборка софта — это специфическая для индустрии область. Но вот, скажем, какой-нибудь YouTrack можно использовать и в не-айтишной компании. Скажем, я в JUG.ru Group делаю конференции, мы для работы используем JIRA. Мы используем её как конструктор бизнес-процессов, используем её API для интеграции с разными внешними формочками, и это крутейшая вещь! Стейт-машина, фактически. Думали ли вы о том, чтобы выходить с тем же YouTrack на какие-то не-айтишные, не-софтверные рынки?

— Он используется и у не-айтишников. Есть люди, которые делают системы продаж на YouTrack. У них какая-то форма, в которой клиент заполняет какие-то поля, в результате это оказывается в YouTrack issue, там настроен workflow-процесс обработки этого заказа, и всё.

— То есть тоже как классическая стейт-машина.

— При этом, поскольку всё кастомизируется и там навороченные workflow на MPS можно рисовать, то да. Но всё это инициатива конкретных пользователей, и YouTrack туда пришёл в эти компании через каких-то девелоперов. Для того, чтобы делать продукт, ориентированный на бизнес в целом, надо научиться заходить к этому бизнесу с каких-то сторон, про которые мы толком не знаем. И, может быть, это и было бы полезно, но, с другой стороны, у нас есть наша любимая пользовательская база, о которой мы многое знаем, что можем сделать для неё в разы больше. И нам не нужно будет придумывать какую-то историю про то, чем JetBrains на данный момент не является.

О конкуренции с Microsoft

— Мы немного затронули тему Eclipse, IBM, и это, видимо, было начало двухтысячных. Сейчас вы выводите на рынок с Rider.

Это вообще было очень смешно, потому что год назад в «Без Слайдов» пришёл Серёга Шкредов, и на vjq вопрос «Будете ли вы делать C# IDE?» ответил: «Нет, ты что!» А через неделю вышел анонс, что JetBrains такую IDE таки делает. Было весело!

Вы сейчас, фактически, выходите на рынок против Microsoft. Rider — это конкурент Visual Studio, который отъест у неё некоторую долю рынка. И это немного отличается от ситуации с Java, потому что там был отдельно вендор, который делал технологию Java (в то время — SUN Microsystems), и были отдельно вендоры, которые делали для нее IDE — IBM и вы. Была сановская технология и две компании, которые делали для нее тулинг.

.NET — это технология, которая фактически принадлежит Microsoft, несмотря на все их опенсорсы. Они ваши партнёры, ваш ReSharper работает поверх их Visual Studio, и так далее. Имея весь этот сложный бэкграунд, выводить на рынок конкурирующий продукт — это страшно, не страшно? Как вы это всё видите?

— Смотри. Во-первых, кроме Sun Studio, NetBeans, был ещё JBuilder и куча других игроков. «Конкурент Visual Studio» совсем не означает «конкурент Microsoft», потому что Microsoft — большой. Microsoft как компания в целом, заинтересован, чтобы их платформа была как можно более широко используема. Для платформы здоровая конкурентная среда, в которой есть тулинг, инфраструктура, является конкурентным преимуществом. Одной ногой мы их конкуренты, потому что отъедаем у них какую-то денежку, которую недополучит Visual Studio, но другой ногой мы привлекаем к ним новых клиентов, которые сядут в Azure и будут писать на .NET.

— Очень хорошо, что ты сказал про Azure. У меня постоянно происходят разговоры в индустрии, и один человек из Microsoft год назад мне сказал следующее: «Для нас .NET — это legacy-технология». Он сказал, что ставки делаются на какие-то другие вещи: на мобайл, на Azure, на IoT. И, в принципе, это хорошо видно по тем маркетинговым активностям, которые они сейчас делают.

Когда вы делаете Rider, который позиционируется как C# IDE, учитываете ли вы, что у Microsoft немножко другое направление и видение и с Azure, и с мобильными вещами…

— Microsoft большой. Microsoft — это не человек, который может принять для себя решение, что он пойдёт на запад, а не на север. Microsoft может пойти во все стороны одновременно, потому что их 70 000 человек (на самом деле, более 100 000 — прим. авт.). Если они будут развивать Azure, это не значит, что они не будут развивать .NET.

Понятно, что они, наверное, сейчас не делают на .NET главную ставку. Понятно, что история с мобильным Microsoft не взлетела, и это, похоже, стало ясно самому Microsoft. Тем не менее, Enterprise-приложения во всяких банковских структурах в большом количестве пишутся на .NET. Банки могут хотеть, например, слезть с виндовой инфраструктуры на Linux, потому что это дешевле операционно. Для этого они сядут на Mono или .NET Core, отсюда есть необходимость в кроссплатформенной разработке. Есть Xamarin — тоже некоторая кроссплатформенная история.

— Microsoft идёт в Linux Foundation.

— А все везде идут. Вот Google идёт в .NET Foundation.

— Получается, что у гигантов индустрии есть интересы вообще везде?

— Конечно. Это подтверждает то, о чем я говорю. Они и не должны ставить на какую-то одну лошадь.

Об отношении к деньгам

— Ещё интересная история — то, что вы частная компания. Вас пытались ли купить?

— Да.

— Приходили предложения о покупке, и они как-то обсуждались. Что вы в этой ситуации чувствовали, как принимали решение и за счёт чего до сих пор остались компанией без IPO и не принадлежащей другой компании?

— Какая-то философщина сейчас пойдёт. Смотри: по идее, бизнес делается с целью зарабатывания денег.

— В уставе любого ООО написано: «с целью извлечения прибыли». Философствования философствованиями, а в уставе у компании должно быть это!

— Конечно, написано. Но у нас в JetBrains есть ощущение, что зарабатывание денег является не целью, а некоторым средством для того, чтобы делать интересные и полезные вещи. Чем больше мы заработаем денег, тем более интересные и полезные вещи мы сможем сделать.

Периодически возникает ситуация, когда то, что мы сделали, интересно какому-то большому игроку. Потому что повторять всю эту историю — дорого, долго, пока ни у кого ещё не получилось, и 15 лет ждать, пока оно вырастет, а может, не вырастет… В общем, дешевле купить, сколько бы это ни стоило. Но нам-то это зачем?

— То есть вам это не нужно?

— Вот exit: представляешь, ты делаешь 15 лет классный продукт, а потом тебе предлагают много денег (ну, ты и так много имеешь, но предлагают вообще очень много денег), и ты меняешь дело жизни на кучку денег. Зачем?

— Это интересный подход. Сейчас вокруг мы видим огромную истерию вокруг стартапов, и недавно даже был на эту тему обозленный пост на Медиуме. Мне очень понравилась мысль оттуда, что мы живём в мире, в котором «стартаперского дискурса» стало как-то очень много. Сам подход «сделать что-то и продать это кому-то за миллионы» становится чуть ли не доминирующим в мире. И вы на этом фоне смотритесь очень…

— Инородно.

— Да, правильное слово. Как вам удаётся удержаться?

— От какого соблазна?

— Ну вот приходит к вам Oracle, предлагают котлету денег, 10 миллиардов.

— Ну, ты загнул, но…

— Ну я же не знаю цены, говорю наобум. Многие люди, особенно стартаперская среда, привыкли оперировать словами «инвестиция», «цена» и всеми этими страшными аббревиатурами, которые были в том самом посте. Очень интересно, что вы вообще это для себя не рассматриваете. Вы не чувствуете этого давления? Мне кажется, это должно создавать давление. Должна ли быть цель какая-то за пределами денег?

— Ну конечно. Много денег банально тяжело осмысленно потратить. А если ты пытаешься заработать деньги чисто ради спорта, то надо откровенно признаться себе, что это спорт. «Вот он заработал два миллиарда, а я пять. Кто круче? Я». Нет.

— Вы сильно выросли. Вы растёте, как я понимаю, на десятки процентов в год, если не быстрее…

— У нас, как ни странно, линейный рост: мы нанимаем порядка 50-70 человек в год.

— Это по количеству людей, а по деньгам — у вас, очевидно, экспонента. А не боитесь, что выйдете на плато, когда, условно, съели всех Java-программистов, и на этом всё остановится, и надо что-то делать? У вас нет инвесторского давления «вы должны расти, должны больше денег», понятно, что частной компании в этом смысле чуть легче — но ощущаете ли вы сами, что плато близко? Насколько далеко до него, по твоим ощущениям?

— Возможно ли плато? Конечно, возможно, куда денется. Я думаю, что запас есть лет на пять.

— Вы уже начинаете думать о том, что вы будете делать дальше?

— Конечно! Kotlin, например. И интегрированную среду для команд разработчиков. И ещё у нас есть инициатива вложиться в образование.

— Это история со Stepik.org?

— Это целый комплекс историй.

По вашим ощущениям, сам IT-рынок растёт? Количество Java-программистов, .NET-программистов, PHP-программистов увеличивается с каждым годом?

— Суммарное число — да, конечно. Есть мнение, что софт вообще всё сожрёт.

— Герман Греф, например, говорил год назад на гайдаровском форуме, что Сбербанк будет трансформироваться из банка в IT-компанию.

— Надо понимать, что для банка это чрезвычайно сложная трансформация. Я не могу представить себе, как это фактически будет реализовано. Но, тем не менее, надо отдать Грефу все возможные кредиты, что он вообще про это задумывается, что он такие цели ставит, это просто здорово.

О том, кто такой Product Marketing Manager

— У вас есть должность, которая называется Product Marketing Manager (далее — PMM). Что это за история, придумывали ли вы сами или откуда-то взяли, и довольны ли вы тем, что в итоге получилось?

— Ой, сразу распишусь в собственной безграмотности: я не знаю, спёрли ли мы или это наша придумка. Но сложилось очень здорово. Это была такая трансформация. Сначала у нас был отдел маркетинга. После того, как программисты написали какую-то фичу и сделали релиз, нужно было побеседовать со специальными людьми, рассказать «смотрите, у нас в релизе, как нам кажется, такие-то фичи есть, напишите блог-пост». Потом приходил блог-пост, глядя на который, я выбирал весь свой лимит матерных слов, вырывал все оставшиеся волосы на голове… Эти посты подходили для продажи зубной пасты, пива. Превосходные термины…

— «Awesome», «perfect», «brilliant», «excellent»… У меня закончился словарный запас!

— Приблизительно так. Причём у человека есть словарный запас приблизительно таких эпитетов, и он по одному подставляет их к очередной фиче.

— Нельзя же повторять одно и то же слово, ты должен чередовать awesome и perfect!

— Человек с образованием, который умеет писать тексты, понимает, что нельзя, а что можно. Но у программистов, нашей целевой аудитории, есть очень серьёзный булшит-фильтр: если ты видишь булшит, срабатывает флаг в голове. Я не могу извлечь семантику из текста, в котором есть определённый уровень булшита. Текст должен быть содержательным, а не красиво и правильно написанным. Выяснилось, что нам нужны люди, которые могут написать такие тексты.

А потом выяснилось ещё, что они не могут написать такие тексты, если они не являются частью команды. Если они не понимают семантики слов, которые пишут, если они просто делают редактуру, то никакой гениальный человек не может сделать хороший не-булшитовый текст. Так мы пришли к тому, что у нас человек просто сидит в команде, пишет тексты, общается с пользователями наравне с программистами и доносит миру, что происходит.

Потом выяснилось, что в каждом продукте такой человек есть, и что они должны общаться между собой, чтобы JetBrains выглядел как не две-три кучки разрозненных чуваков, каждая из которых делает свой продукт по собственному разумению, а как слаженная общая история. И теперь эти PMM’ы, с одной стороны, в продукте, а с другой, они общая кучка, которая постоянно между собой общается. И кроме PMM’ов, мы пытаемся эту историю в других областях применять, вроде DevOps, например.

— Возвращаясь к истории про догфудинг. PMM-ы у вас вырастают из разработчиков, а не из маркетологов. Встает вопрос про необходимость маркетингового образования для них, про понимание функционирования рынков и т.п. Но они же бывшие инженеры. Как одно матчится с другим?

— Очень кусочно. Я не могу сказать, что мы следуем всем новомодным тенденциям в маркетинге, что мы прочитали все умные книжки. Кто-то из PMM-ов читает профессиональную литературу, кто-то пытается заниматься самообразованием, кто-то работает по наитию, кто-то внимательно слушает, что ему говорят коллеги, а кто-то, наоборот, внимательно не слушает, потому что коллеги говорят полную хрень. Каждый себе на уме.

На самом деле, в PMM’ы приходят самыми разными путями. Есть люди, которые не инженеры, не умеют писать продакшен-код. Но, в принципе, понимают, как это делается. Есть среди них и боевые инженеры, что-то делавшие, но у которых больше развиты социальные функции.

О найме сотрудников

Есть какие-то ключевые функции бизнеса: разработка, продажи, маркетинг, HR. Если не секрет, что из этого всего для тебя — головная боль? Или где ты видишь наибольшие перспективы?

— Те проблемы, которые я вижу, я пытаюсь решать. Но есть проблемы, которые я не вижу. Есть проблемы, которые неизбежно должны вырасти просто потому, что компания растёт — коммуникации, может быть, обмен информацией, стандартизация, какие-то политики, и так далее.

— По тем признакам, которые видны снаружи, вы скорее стартап, но по финансовым показателям вы — серьёзный бизнес. Как вы это матчите?

— Это очень просто матчится, вообще нет никакого конфликта. У нас организация такая, что команда, которая делает продукт, автономна. В принципе, ей ничего ни от кого не нужно. Нужны определённые сервисные функции: чтобы в офисе было тепло, сухо и комфортно, чтобы была техника, инфраструктура работала, чтобы был налаженный диалог с HR’ом, приходили хорошие новые люди. Если эти проблемы решены, команда сработает сама. Она зарабатывает N денег. Другая точно такая же команда заработает 2N денег. Ну и что?

— HR — это же не только про найм людей. У тебя есть бизнес, и ты, наверное, в идеале хочешь понять, какие нужны люди, чтобы бизнес развивался. «А тут мне нужно закрыть дыру». И это довольно трудно, особенно с точки зрения программирования: понять, какой программист мне нужен, чтобы он вытянул новый продукт. Вот, условно говоря, Андрей Бреслав — Language Architect. Это же вообще ни фига не простая задача — найти архитектора языка.

— Ты же понимаешь, что мы не выходили на рынок, не писали вакансию на HeadHunter: «Нам нужен Language Architect, чтобы писать язык». Так не делается. Просто встретились, и выяснилось, что человек может делать эту работу. До этого мы не знали, что он нам нужен. И так же во всём остальном.

У нас есть другая проблема (не знаю, правда, проблема ли это). Мы не можем нанимать людей на руководящие позиции. То есть мы много про это думали, но я до сих пор не понимаю, как это делать.

— Такой человек не интегрируется в компанию?

— Cкорее всего, интегрируется, мы просто не знаем, с какой стороны к этому подойти. Скажем, пусть у нас есть продукт, в котором слабый руководитель — чисто теоретически, я ничего не имею в виду. Как? Что, перебрать? Это же не секретарь на ресепшен, про которого можно за полтора часа собеседования понять, что он из себя представляет с точки зрения этих функций.

— Люди, которые у вас работают, изучали много математики, изучали программирование, IT. А когда с человеком происходит трансформация и он становится руководителем, ему становятся нужны совершенно другие компетенции. Нет ли здесь ловушки?

— У нас обычно руководителем де-юре становится тот, кто уже является руководителем своей команды де-факто.

— И вы просто официально это закрепляете.

— Да. То есть это человек, у которого есть авторитет среди коллег, к которому прислушиваются, которого зовут что-то обсудить. Поэтому все нужные скиллы для того, чтобы работать над этим продуктом в этой команде, у него обычно есть.

О Kotlin Native

— Понятно. Наверное, последний вопрос — про Kotlin Native. Для меня важным показателем того, насколько серьёзно компания относится к продукту, является то, какие люди там работают. Сейчас в Kotlin Native появились Николай Иготти и Роман Елизаров. Приход таких мощных специалистов — это для меня показатель, что вы делаете на это направление серьёзную ставку. Ты можешь про это рассказать — почему именно Kotlin Native? Сейчас эта история (может быть, не для рынка, но вот для меня конкретно) выглядит громче и занимает в моей башке даже более серьёзную позицию, чем просто Kotlin.

— Потому что ты, что называется, слишком много знал про другую платформу и как она устроена. Смотри, глобальная история про Kotlin должна заключаться в том, что на Kotlin пишут на всём и подо всё. Язык, как мне кажется, получился хорошим и развиваемым в этом направлении. От этого возникают прекрасные сингулярные фичи, и доказательства этого мы видим в джаваскриптовом мире, где возник Node.js. Что такое Node.js? Может быть, меня сейчас закидают (хотя через экран это сложно сделать), но он ведь сделан ровно для того, чтобы можно было писать один и тот же код и на клиенте, и на сервере.

— Ну, не только. Есть вторая история «я уже знаю JavaScript, но вот мне срочно надо писать серверный код».

— Мне кажется, что это ловушка, потому что язык здесь очень маленькая часть. Сервер пишется совсем не так, как клиент, просто потому что там другая история, другая логика процесса.

— Я всё понимаю, но если у меня в руке молоток, я умею писать на JavaScript, то всё остальное мне начинает казаться гвоздём.

— Каждый из этих факторов приводит немножко разных людей в Node.js. Те люди, о которых ты говоришь — это очень публичная история. Но ведь очень серьёзные приложения пишутся на Node! Просто потому что у тебя исчезает некоторый барьер между клиентом и сервером, исчезает необходимость общаться в примитивном JSON’е. Можно писать фреймворки высокого уровня, которые синхронизируют данные в реалтайме, и прочая, и прочая.

Но на JavaScript. Если бы вместо джаваскрипта здесь был существенно более качественный язык программирования и существенно более качественная среда исполнения, то, наверное, это было бы круто.

— Правильно ли я понимаю, что, условно говоря, сейчас основной конкурент Kotlin-а — это JavaScript?

— Интересная точка зрения. Не знаю.

— JS сейчас самый быстрорастущий язык в индустрии, это видно по многим параметрам.

— Kotlin-у такие темпы роста, конечно, пока не снятся. В абсолютном выражении — в относительном, может, и снятся, я не считал. Ну да, наверное, его можно так рассматривать. И отсюда естественным образом вырастает Kotlin Native, потому что, кроме браузеров, будут ещё другие устройства. Это телефоны, это IoT. В IoT всё совсем плохо с точки зрения инфраструктуры, тулинга…

— Там со всех точек зрения плохо!

— Поэтому, если начать с языка программирования с хорошим тулингом, который при этом на сервере может логику обслуживать, то win-win, profit.

— Oracle, например, заговорил про Internet of Things, мне кажется, ещё лет пять назад, я ещё там только начинал работать, и тогда вообще никто не понимал, что это такое. Было только слово «IoT» и были гиганты со своими, отличающимися друг от друга, понятиями и концепциями. Казалось, что пройдёт два-три года, и они о чём-то договорятся. Сейчас стало чуть больше понимания, что такое IoT — много маленьких устройств, Big Data в бэкенде, но полного понимания до сих пор нет. Все с этим носятся, но никто этого не видит, не чувствует и, на самом деле, не использует. А потенциально все орут, что это наше будущее. Что ты думаешь по этому поводу?

— Понятия не имею.

— То есть вы на этот рынок не смотрите?

— Нам не надо на него смотреть. Мы точно знаем, что люди будут писать программы. Есть, конечно, вариант, когда люди будут, не знаю, наговаривать программы или брать их прямо из мозга, но пока, на ближайшую перспективу, люди пишут программы на языках программирования. И, кажется, нет обоснования того, что эти языки программирования обязательно должны быть какими-то динозавроподобными. То есть мне сложно обосновать, почему нужно писать именно на C, а не на языке, который ближе к Котлину.

— То есть что бы это ни было — или cloud, или IoT, или что угодно — JetBrains будет делать для этого инструменты?

— Да. И как в мультике про Смешариков, будем тапочки выдавать. В смысле IDE продавать.


ссылка на оригинал статьи https://habrahabr.ru/post/318842/

Умная теплица в Telegram

Добрый день. На нашем участке имеется теплица. Её главная проблема — перегрев в жаркое время, т.к. рассчитана в первую очередь на сибирскую весну. Единственный выход — постоянно открывать/закрывать двери и окна, чтобы поддерживать температуру. Но это не всегда возможно. А если это не сделать, то температура поднимается до +50 градусов, что явно не хорошо. А вечером всё можно заморозить. Так и началась её автоматизация.

image

В первую очередь мы купили Raspberry Pi 2. Разобравшись с ним, подключили датчик DS18B20 по этой статье. Затем были куплены два б/у автомобильных стеклоподъёмника. Как и все DC двигатели, они движутся в зависимости от полярности. Поэтому к каждому двигателю подключаем два реле: одно для открытия, другое для закрытия. Эти реле уже через транзисторы подключаем к самим портам GPIO. И питаем это всё дело аккумулятором 12V. Так же, чтобы не сжечь двигатели, в крайних положениях окна были установлены концевые выключатели, и в случае, если окно открылось/закрылось полностью рвут сеть.

image

image

А для связи мы используем WiFi адаптер TP-LINK с усовершенствованной антенной «Двойной квадрат» для уверенного приёма соседского WIFI домашнего WIFI роутера, который находиться на расстояние 40 метров.

image

Теперь пишем программу для управления этими приводами. Был выбран язык Python, т. к. у него нормальная поддержка Raspberry Pi и конкретно GPIO портов. Для того, чтобы открыть окно, нам нужно подать +3.3V на транзистор, который активирует реле, и то начнёт открывать окно. Чтобы его закрыть, делаем то же самое, только в это случаем наше реле подключено наоборот к приводу. Но на Raspberry мы просто подаём ток то на один порт, то на другой. Мы решили, что если температура больше 26 открываем окно в течение 1 секунды. Затем ждём 3 минуты. Если опять жарко, то открываем второе окно в течение секунды. Ждём опять 3 минуты, и делаем заново. То же самое с закрытием, только тут температура должна быть ниже 24 градусов. А вот и код:

import RPi.GPIO as GPIO import time import os import datetime  GPIO.setmode(GPIO.BOARD) GPIO.cleanup() GPIO.setup(31, GPIO.OUT) GPIO.setup(33, GPIO.OUT) GPIO.setup(35, GPIO.OUT) GPIO.setup(37, GPIO.OUT)  #Получаем температуру def gettemp():   if os.path.isdir("id датчика"): #Если датчик подключён, то считываем значение     tfile2=open("/sys/bus/w1/devices/id датчика")     ttext2=tfile2.read()     tfile2.close()     temp2=ttext2.split("\n")[1].split(" ")[9]     t2=float(temp2[2:])/1000     print t2   else: #если нет, то задаём дефолтное     print ('File not found')     t2==24   return t2  t2=24 #Задаём дефолтное значение для датчика while True: вечный цикл t2=gettemp()   if    t2<24: #Если температура меньше 24, то закрываем окно в течение секунды           GPIO.output(37, 1)         print ("close1")         time.sleep(1)         GPIO.output(37, 0)    elif  t2>26: #Если больше 26, то открываем окно в течение секунды         GPIO.output(35, 1)         print ("open1")         time.sleep(2)         GPIO.output(35, 0)            else: #Иначе ничего не делаем         print ("none1")   time.sleep(180)#Ждём 3 минуты  #Опять читаем температуру t2=gettemp()  #Всё то же самое, только со вторым окном.   if    t2<24:         GPIO.output(33, 1)         print ("close2")         time.sleep(1)         GPIO.output(33, 0)    elif  t2>26:            GPIO.output(31, 1)         print ("open2")         time.sleep(1)         GPIO.output(31, 0)          else:         print ("none2")   #Опять ждём 3 минуты   time.sleep(180) 

А теперь начинается шоу для тех, кому физика не интересна.

Установив Apache на дистрибутив Raspbian, мы в течение месяца не могли достучаться до странички из интернета. Что только не делали. Настраивали порты, открывали их, ничего не помогала. Причём в локальной сети всё работали. Потом мы узнали печальную правду: мы находимся за NAT. И услуг по выделенному IP наш оператор для предоставляет (Привет сотрудникам Регион Телекома). Перебирали много обходных методов, но ничего не выходило. Пытался сделать веб интерфейс на хостинге, но для синхронизации базы данных тоже нужен IP. Брокер IPv6 к тому времени уже закрылся. А делать VPN дорого, ведь хочется всё бесплатно. И тут решили использовать Telegram бота. Как оказалось он имеет два режима: постоянный опрос сервера и отправка сообщений прямо к нам. Первый вариант подходил, т.к. не требует от нам IP адреса. Покопавшись в интернете нашёл библиотеку: pytelegrambotapi. И принялся за написание кода. Правда выходили и проблемы. Еле найденная MySQL библиотека отказывалась писать в базу данных, но при это читала из неё всё нормально. Пришлось делать костыль: передавать данные в файл, хранящийся в ОЗУ, затем запускать bash скрипт, который считает данные и занесёт в БД.

Делаем файл config.ini, туда кидаем:

[mysql] host = localhost database = telegram user = root password = secret</code> Не забываем данные заменить на свои.  	Создаём файл python_mysql_dbconfig.py , со следующим содержимым:  <source lang="python">from configparser import ConfigParser   def read_db_config(filename='config.ini', section='mysql'):     """ Read database configuration file and return a dictionary object     :param filename: name of the configuration file     :param section: section of database configuration     :return: a dictionary of database parameters     """     # create parser and read ini configuration file     parser = ConfigParser()     parser.read(filename)       # get section, default to mysql     db = {}     if parser.has_section(section):         items = parser.items(section)         for item in items:             db[item[0]] = item[1]     else:         raise Exception('{0} not found in the {1} file'.format(section, filename))       return db

Так же нам нужно создать файл python_mysql_connect2.py, с вот таким содержимым:

from mysql.connector import MySQLConnection, Error from python_mysql_dbconfig import read_db_config  def connect():     """ Connect to MySQL database """      db_config = read_db_config()      try:         print('Connecting to MySQL database...')         conn = MySQLConnection(**db_config)          if conn.is_connected():             print('connection established.')         else:             print('connection failed.')      except Error as error:         print(error)      finally:         conn.close()         print('Connection closed.')  if __name__ == '__main__':     connect() 

Теперь мы всё подготовили для работы с БД.

Отвлечёмся немного от базы данных и перейдём непосредственно к общению с ботом. Ну как обычно, пишем @BotFather, и берём у него токен. Создаём файл config.py, и пишем в него две строчки:

# -*- coding: utf-8 -*- token = 'Ваш токен' 

Я решил реализовать в боте три функции:

  • Получение температуры
  • Получение снимков
  • Управление окнами

С первым всё просто, по запросу читаем файл с температурой, и отправляем это пользователю.

Со снимками посложнее. Я использую утилиту Motion. В её параметрах проси класть в папку в оперативной памяти снимки, ну допустим каждые 30 секунд. И делаем файлы с одинаковыми имена, и они просто заменяют друг друга. А потом по запросу отправляем файл пользователю.

Ну и третий, самый сложный модуль: управление окнами. У меня главная задача: чтобы работала автоматика, но если нужно, то мы её можем отключить. Делал я это так. Создал в оперативной памяти очередной файл. Когда мы отправляем запрос на открытие/закрытие, приоткрытие, призакрытие окна или на включение/выключение автоматики бот пишет в этот файл номер команды. Каждые пять секунд программа управления окнами считывает этот файл, и если распознаёт команду, выполняет её. После выполнение в этот же файл пишет, что всё прошло успешно. Бот опять читает файл, и уведомляет нас, что команда выполнена.

Ну а теперь исходный код. Сначала та же самая программа для открывания окон, только уже переделанная под бота(temp.py):

import RPi.GPIO as GPIO import time import os import datetime  GPIO.setmode(GPIO.BOARD) GPIO.cleanup() GPIO.setup(31, GPIO.OUT) GPIO.setup(33, GPIO.OUT) GPIO.setup(35, GPIO.OUT) GPIO.setup(37, GPIO.OUT)  #Пишем в файл, что готовы к работе f = open('/mnt/raw/wind', 'w') f.write('OK') f.close()  #Пишем, что автоматика включена f = open('/mnt/raw/pos', 'w') f.write('1') f.close()  #получаем температуру def gettemp():   if os.path.isdir("/sys/bus/w1/devices/id датчика"): #Если датчик подключён, то считываем значение     tfile2=open("/sys/bus/w1/devices/id датчика/w1_slave")     ttext2=tfile2.read()     tfile2.close()     temp2=ttext2.split("\n")[1].split(" ")[9]     t2=float(temp2[2:])/1000     print t2   else: #если нет, то задаём дефолтное     print ('File not found')     t2==24   return t2  #Включаем автоматику по дефолту i=1 #Дефолтная температура t2=24  #Читаем команды от бота def info():     f = open('/mnt/raw/wind')     com = f.read()     f.close()     return com  #Отвечаем боту, что всё успешно def ans():     f = open('/mnt/raw/wind', 'w')     f.write('OK')     f.close()     print ("OK")  #Анализируем команды def rob():     c = info()     if c=="10":         GPIO.output(37, 1)         print ("close1")         time.sleep(3)         GPIO.output(37, 0)         ans()     elif c=="11":         GPIO.output(35, 1)         print ("open1")         time.sleep(2)         GPIO.output(35, 0)         ans()     elif c=="12":         GPIO.output(37, 1)         print ("close1")         time.sleep(3)         GPIO.output(37, 0)         ans()     elif c=="13":         GPIO.output(35, 1)         print ("open1")         time.sleep(1)         GPIO.output(35, 0)         ans()     elif c=="20":         GPIO.output(33, 1)         print ("close2")         time.sleep(3)         GPIO.output(33, 0)         ans()     elif c=="21":         GPIO.output(31, 1)         print ("open2")         time.sleep(3)         GPIO.output(31, 0)         ans()     elif c=="22":         GPIO.output(33, 1)         print ("close2")         time.sleep(1)         GPIO.output(33, 0)         ans()     elif c=="23":         GPIO.output(31, 1)         print ("open2")         time.sleep(1)         GPIO.output(31, 0)         ans()     elif c=="30":         global i         i=0         ans()         f = open('/mnt/raw/pos', 'w')         f.write('0')         f.close()         print('30')         global i         i=0         ans()     elif c=="31":         f = open('/mnt/raw/pos', 'w')         f.write('1')         f.close()         print('31')         global i         i=1         ans()          while True:  #Читаем и выполняем команды  rob()  #Проверяем, включена ли автоматика  if i==1:    gettemp()    if    t2<24:           GPIO.output(37, 1)         print ("close1")         time.sleep(1)         GPIO.output(37, 0)    elif  t2>26:          GPIO.output(35, 1)         print ("open1")         time.sleep(2)         GPIO.output(35, 0)    else:         print ("none1")           #Ожидаем 3 минуты, и в течение этого времени читаем команды   j=0   while(j<36):       rob()       time.sleep(5)       j=j+1       if i==0:           break   gettemp()    if    t2<24:         GPIO.output(33, 1)         print ("close2")         time.sleep(1)         GPIO.output(33, 0)           elif  t2>26:            GPIO.output(31, 1)         print ("open2")         time.sleep(1)         GPIO.output(31, 0)    else:          print ("none2")    j=0   while(j<36):       rob()       time.sleep(5)       j=j+1       if i==0:           break 

Но а теперь поговорим про самого бота. Как я уже говорил, я использую библиотеку PyTelegramBotApi. Если обратиться к документации на GitHub, то можно понять что для обработки команд бот использует хендлеры. Хендлер — это событие в нашей программе, определяющие действие. В нашей случае это определенная фраза в сообщение. А действие это всё что мы можем сделать в языке python. В данном случае мы будет присылать пользователю какую-нибудь информацию пользователю или записывать команды для окон в файл. В основном наша программа состоит из этих самых хендлров и команды опроса сервера.

Но так же я сам написал и добавил ещё одно интересную вещь: блок авторизации. Ну как понятно из названия, он сделан для защиты нашей теплицы от несанкционированного доступа. Он работает просто. При первом подключение к боту он запрашивает у нас пароль. Если мы его вводим правильно, бот добавляет нас в базу данных, и при следующих подключениях нам уже авторизироваться не нужно. Бот узнаёт нас при помощи chat-id. Chat-id последнего пользователя храним в переменно, чтобы всё время не дёргать базу.

Теперь создаём файл daba.py и пишем туда вот это:

from mysql.connector import MySQLConnection, Error from python_mysql_dbconfig import read_db_config import time  def getkey(): #Читаем пароль для бота     try:         dbconfig = read_db_config()         conn = MySQLConnection(**dbconfig)         cursor = conn.cursor()         cursor.execute("SELECT key2 FROM tkey where id=0")          row = cursor.fetchone()          return row         print(row)         except Error as e:         print(e)      finally:         cursor.close()         conn.close() def sendup(): #Отправляем время запуска бота (не работает)     stime=time.time()     query = "INSERT INTO uptime(datetime, also) " \     "VALUES(now(), 20)"     args=(stime)     try:         dbconfig = read_db_config()         conn = MySQLConnection(**dbconfig)         cursor = conn.cursor()         cursor.execute(query)          row = cursor.fetchone()          return(row)         print(row)         except Error as e:         print(e)      finally:         cursor.close()         conn.close() def getid(idi): #проверяем есть ли id пользователя в базе     query="SELECT accecpt FROM users WHERE chatid ='"+str(idi)+"'"     try:         dbconfig = read_db_config()         conn = MySQLConnection(**dbconfig)         cursor = conn.cursor()         cursor.execute(query)          row = cursor.fetchone()         #print (str(row))         if str(row)=="None":             return 0;             print (0)         else:             return 20;          except Error as e:         print(e)      #finally:         #cursor.close()         #conn.close() def newuser(idi): #Добавляем пользователя в базу данных     query = ("INSERT INTO users SET `chatid`='12345'")     try:         dbconfig = read_db_config()         conn = MySQLConnection(**dbconfig)         cursor = conn.cursor()         cursor.execute(query)          row = cursor.fetchone()          print(row)         except Error as e:         print(e)         return(e)      finally:         cursor.close()         conn.close()  if __name__ == '__main__':     query_with_fetchone() 

Так же давайте сразу сделаем ещё несколько вспомогательных скриптов. Создаём файл newuser.sh и пишем в него:

#!/bin/bash a=`cat /mnt/raw/user` cat /dev/null > /mnt/raw/user  mysql -u root -pkoshak << EOF use telegram; INSERT INTO users(chatid) VALUES('$a'); EOF 

И создадим два скрипта для запуска бота и программы окон:

#!/bin/bash i=0 while [ $i = 0 ] do echo New python sleep 5 python3 bot.py done 

И ещё один:

#!/bin/bash i=0 while [ $i = 0 ] do echo New python sleep 5 python3 temp.py done 

«Зачем мы это делаем?» спросите вы. А тут дело в том, что иногда из-за нестабильного интернет соединения, или ошибки на сервера Telegram программа может вылететь. А скрипт её гоняет в вечном цикле: вылетела — запустил через 5 секунд снова. А для окон я сделал это на всякий пожарный: вдруг тоже из-за сбоя программа вылетит, а нас в теплице нет, вернёмся и будет у нас томатный суп или помидорное мороженное.

Ну и теперь самое главное, скрипт самого бота (bot.py):

# -*- coding: utf-8 -*- import config import telebot import subprocess import time from telebot import types import datetime import os from daba import getkey from daba import sendup from daba import getid #from daba import newuser #from temp import tep import os  #Создаём файл f = open('/mnt/raw/user', 'tw', encoding='utf-8') f.close()  global par par=0  #Текст для неавторизированного пользователя global a a="Вы не авторизированны. Пройдите авторизацию командой /auth [пароль]"  #Функция получение температуры def get_temp():   if os.path.isdir("/sys/bus/w1/devices/id датчика"):      tfile2=open("/sys/bus/w1/devices/id датчика/w1_slave")     ttext2=tfile2.read()     tfile2.close()     temp2=ttext2.split("\n")[1].split(" ")[9]     t2=float(temp2[2:])/1000     return t2    else:     print ('File not found')    #Пароль keyword=str(getkey())[2:-3]  #Конфигурация токена bot = telebot.TeleBot(config.token) print (sendup()) #Создание кастомной клавиатуры  #########################Клавиатура авторизации########################################## markup2 = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду markdown = types.ReplyKeyboardHide() #Деактивация itembtn5 = types.KeyboardButton(' Авторизация') #Название кнопки 5 markup2.add(itembtn5) #Занесение кнопок в матрицу #########################Клавиатура авторизации##########################################   #########################Клавиатура главного меню########################################## markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn1 = types.KeyboardButton(' Прислать снимок') #Название кнопки 1 itembtn4 = types.KeyboardButton(' Управление окнами') itembtn2 = types.KeyboardButton(' Прислать температуру') #Название кнопки 2 markup.add(itembtn1, itembtn4, itembtn2) #Занесение кнопок в матрицу #########################Клавиатура главного меню##########################################   #########################Ещё кнопки##########################################  markup3 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn10 = types.KeyboardButton(' Выключить автоматику ') #Название кнопки 10 itembtn11 = types.KeyboardButton('️ Ручное управление') itembtn12 = types.KeyboardButton(' Назад') markup3.add(itembtn10, itembtn11, itembtn12) #Занесение кнопок в матрицу  markup4 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn13 = types.KeyboardButton(' Включить автоматику ') #Название кнопки 13 markup4.add(itembtn13, itembtn11, itembtn12) #Занесение кнопок в матрицу  markup5 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn14 = types.KeyboardButton(' Первое окно') #Название кнопки 14 itembtn15 = types.KeyboardButton(' Второе окно') #Название кнопки 15 itembtn16 = types.KeyboardButton('️ Назад') #Название кнопки 16 markup5.add(itembtn14, itembtn15, itembtn16) #Занесение кнопок в матрицу  markup6 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn17 = types.KeyboardButton('️ Открыть окно ') #Название кнопки 17 itembtn18 = types.KeyboardButton('️ Закрыть окно ') #Название кнопки 18 itembtn19 = types.KeyboardButton(' Приоткрыть окно ') #Название кнопки 19 itembtn20 = types.KeyboardButton(' Призакрыть окно ') #Название кнопки20 itembtn21 = types.KeyboardButton('️ Назад') #Название кнопки 21 markup6.add(itembtn17, itembtn18, itembtn19, itembtn20, itembtn21) #Занесение кнопок в матрицу  markup7 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn22 = types.KeyboardButton('️ Открыть окно ') #Название кнопки 22 itembtn23 = types.KeyboardButton('️ Закрыть окно ') #Название кнопки 23 itembtn24 = types.KeyboardButton(' Приоткрыть окно ') #Название кнопки24 itembtn25 = types.KeyboardButton(' Призакрыть окно ') #Название кнопки25 markup7.add(itembtn22, itembtn23, itembtn24, itembtn25, itembtn21) #Занесение кнопок в матрицу #########################Ещё кнопки########################################## bot.send_message(45215125, "Перезагрузка")#Вставьте сюда ваш chat-id        #Узнаем состояние автоматики окон def pos():     f = open('/mnt/raw/pos')     com = f.read()     f.close()     return com  #Авторизация def avtor(idi):     global par#Если пользователь храниться в переменной возвращаем ноль     if par==idi:             return 0     else:#Запрашиваем наличие пользователя в БД, если он там есть, возвращаем 0             if getid(str(idi))==20:                 par=idi#Заносим пользователя в переменную                 return 0             else:#Пишем что мы не знаем пользователя                 bot.send_message(idi, "Вы не авторизированны. Пройдите авторизацию командой /auth [пароль]", reply_markup=markup2)                 return 1                @bot.message_handler(regexp=" Авторизация") def auth(message):     bot.send_message(message.chat.id, "Введите /auth [пароль]")  #Тоже аворизация @bot.message_handler(commands=['auth']) def start2(message):     if message.text[6:]==keyword:#Вырезаем пароль из сообщения       if getid(str(message.chat.id))==20:#Проверяем пароль в базе данных, если пользователь там уже есть нам вернётся код 20         bot.send_message(message.chat.id, "Вы уже авторизированы")       else:         global par         bot.send_message(message.chat.id, "Успешно", reply_markup=markup)         par=message.chat.id         #Отправляем chat-id в базу данных         f = open('/mnt/raw/user', 'w')         f.write(str(message.chat.id))         f.close()         os.system('newuser.sh')         print (message.chat.id)         print (par)     else:         bot.send_message(message.chat.id, "Неверно")         print (keyword)         print (message.text[6:])         print (message.chat.id)   # Команда /start @bot.message_handler(commands=['start']) def start(message):      global par      if avtor(message.chat.id)!=0:          print (par)          bot.send_message(message.chat.id, " Вы не авторизированны. Пройдите авторизацию командой /auth [пароль]", reply_markup=markup2)      else: 	     bot.send_message(message.chat.id, " Вы авторизированный пользователь. Наберите /help, для того, чтобы узнать список команд.")    #Команда запроса помощи - /help @bot.message_handler(commands=['help']) def help(message):   if avtor(message.chat.id)==0:      mas=' Данный бот управляет теплицей на моём участке. \n Список команд для помощи, в управление этим ботом:  \n Получить справку - /help \n Остальное всё управляется при помощи клавиатуры :)'      bot.send_message(message.chat.id, mas, reply_markup=markup)      print (message.chat.id, message.text)  	   #Заменить интерфейс командной строки на клавиатуру @bot.message_handler(commands=['show']) def show(message):   if avtor(message.chat.id)==0:      mas='Клавиатура включена'      bot.send_message(message.chat.id, mas, reply_markup=markup)      print (message.chat.id, message.text)    #получить температуру @bot.message_handler(regexp=" Прислать температуру") def temp(message):   if avtor(message.chat.id)==0:      tp=get_temp()      mas='  Температура в теплице: '+str(tp)+'°C'      bot.send_message(message.chat.id, mas)      print (message.chat.id, message.text)       #прислать снимок @bot.message_handler(regexp=" Прислать снимок") def photo(message):       if avtor(message.chat.id)==0:           path='/mnt/raw/photo/foto.jpg' #Путь к папку со снимком          try:              f = open(path, 'rb') #Открытия файла - снимка              bot.send_photo(message.chat.id, f) #Отправка снимка              print (message.chat.id, message.text)          except:              bot.send_message(message.chat.id, "Фоток нет :(")   #Переход в меню окон @bot.message_handler(regexp=" Управление окнами") def windows(message):    if avtor(message.chat.id)==0:        print ("window")        print (pos())        if str(pos())[0]=='1':            bot.send_message(message.chat.id, "Ок", reply_markup=markup3)#Если автоматика включена, то выводим клавиатуру с надписью «Выключить автоматику»        else:             bot.send_message(message.chat.id, "Ок", reply_markup=markup4)#А здесь всё с точность наоборот  #Кнопка назад @bot.message_handler(regexp=" Назад") def windows(message):    if avtor(message.chat.id)==0:        bot.send_message(message.chat.id, "Ок",  reply_markup=markup)  #Выключение автоматики @bot.message_handler(regexp=" Выключить автоматику ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')#Открываем файл        f.write('30')#Пишем туда код команды, в данный момент это 30        f.close()#Закрываем файл        k="No"#Дефолтное значение переменной        while k[0:2]!="OK":#Проверяем ответ             time.sleep(5)#Ждём 5 секунд            f = open('/mnt/raw/wind')#Открываем файл            k = f.read()#Читаем ответ            f.close()#Закрывает            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup4)  @bot.message_handler(regexp=" Включить автоматику ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('31')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup3)  @bot.message_handler(regexp="️ Ручное управление") def windows(message):    if avtor(message.chat.id)==0:        bot.send_message(message.chat.id, "Ок",  reply_markup=markup5)  @bot.message_handler(regexp="️ Назад") def windows(message):    if avtor(message.chat.id)==0:        if str(pos())[0]=='1':            bot.send_message(message.chat.id, "Ок", reply_markup=markup3)        else:             bot.send_message(message.chat.id, "Ок", reply_markup=markup4)  @bot.message_handler(regexp="️ Назад") def windows(message):    if avtor(message.chat.id)==0:        bot.send_message(message.chat.id, "Ок",  reply_markup=markup5)  #Бегаем по меню @bot.message_handler(regexp=" Первое окно") def windows(message):    if avtor(message.chat.id)==0:        bot.send_message(message.chat.id, "Ок",  reply_markup=markup6) @bot.message_handler(regexp=" Второе окно") def windows(message):    if avtor(message.chat.id)==0:        bot.send_message(message.chat.id, "Ок",  reply_markup=markup7)  @bot.message_handler(regexp="️ Открыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('11')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup6)  @bot.message_handler(regexp="️ Закрыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('10')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup6)  @bot.message_handler(regexp=" Приоткрыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('13')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup6)  @bot.message_handler(regexp=" Призакрыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('12')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup6)  @bot.message_handler(regexp="️ Открыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('21')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup7)  @bot.message_handler(regexp="️ Закрыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('20')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup7)  @bot.message_handler(regexp=" Приоткрыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('23')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup7)  @bot.message_handler(regexp=" Призакрыть окно ") def windows(message):    if avtor(message.chat.id)==0:        f = open('/mnt/raw/wind', 'w')        f.write('22')        f.close()        k="No"        while k[0:2]!="OK":            time.sleep(5)                       f = open('/mnt/raw/wind')            k = f.read()            f.close()            print(k[0:2])        bot.send_message(message.chat.id, "Успешно",  reply_markup=markup7)  #Реакция на команды, не приведённые выше @bot.message_handler(content_types=["text"]) def repeat_all_messages(message):    if avtor(message.chat.id)==0:          bot.send_message(message.chat.id, "Я не знаю такой команды. Набери /help, чтобы получить список команд")          print (message.chat.id, message.text)  #Отпрашиваем сервер на наличие новых сообщений if __name__ == '__main__':         bot.polling()

Не забываем указать здесь id датчика, chat-id и путь к разделу в оперативной памяти. Теперь у нас почти всё готово. Качаем этот дамп, и заливаем базу данных на свой сервер, и не забываем смонтировать раздел в оперативной памяти, думаю 10 МБ хватит по горло. Запускаем два наших скрипта-стартера и радуемся. Пароль по умолчанию: telbot. Меняем его в таблице tkey базы данных.

СМС информирование

Так же сделал СМС информирование на случай перегрева. Создаём файл sms.py:

#!/usr/bin/env python # -*- coding: utf8 -*-   """ Автор Титов А.В. t_aleksandr_v@inbox.ru 17.02.2015 """   """ Скрипт предназначен для отправки СМС через сайт sms.ru """ """ Принимает следующие аргументы:"""   """ -i или --idsender - id пользователя на sms.ru""" """ -t или --to - номер телефона получателя в формате 79219996660""" """ -s или --subject - текст сообщения на латинице"""     from urllib2 import urlopen from optparse import OptionParser     def sendsms(idsender,subject,to):       subject = subject.replace(" ","+")     url="http://sms.ru/sms/send?api_id=%s&text=%s&to=%s" %(idsender,subject,to)     res=urlopen(url)   if __name__ == '__main__':       parser = OptionParser()       parser.add_option("-i", "--ваш ключ", dest="idsender", default="ваш ключ", help="ID user on sms.ru", metavar="IDSENDER")     parser.add_option("-t", "--ваш телефон", dest="to", default="ваш телефон", help="to telephone number", metavar="TO")     parser.add_option("-s", "--temperatyra 32", dest="subject", default="Jara tut, otkroy okno", help="Name of subject", metavar="SUBJECT")       (options, args) = parser.parse_args()       sendsms(options.idsender,options.subject,options.to)

Регистрируемся на sms.ru и берём так API-key в разделе для программистов. Так же не забываем указать в скрипте ваш номер телефона.

В программе для управления окон объявляем переменную:

Vr=0

Затем вставляем в вечный цикл этот код:

d = datetime.today() V = d.strftime('%H') V = int(V)  if    (t2>32 and Vr!=V):          print (V)         Vr=V         os.system('/home/samba/sms.py')

В данный момент температура порога 32, смс будут отправляться в случае высокой температуры раз в час, пока она не спадёт.

P.S. В планах на будущее установить управляемый обогреватель и сделать автоматический полив.

Спасибо всем тем, кто дочитал до конца.
ссылка на оригинал статьи https://geektimes.ru/post/284258/