[Модуль] Продукты (app_products)

Разработка дополнительных модулей, подключение различных приложений.

Модератор: immortal

d1MA
Сообщения: 14
Зарегистрирован: Пн дек 11, 2017 9:17 pm
Благодарил (а): 1 раз
Поблагодарили: 0

Re: Модуль Продукты

Сообщение d1MA » Чт дек 21, 2017 10:14 pm

webms писал(а):
d1MA писал(а):у меня в модуле продуктов нечего нет кроме Module "app_products" not found ([module name="app_products" action="admin" instance="adm"])
что делать
установить
Изображение
да я попробовал его устанавливать и удалять
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Пн янв 22, 2018 12:32 pm

Учитывая общую тенденцию к голосовым помощникам и голосовому управлению добавил функцию в этот модуль для интеграции с голосовыми командами.

К примеру Говорим фразу "В холодильнике закончились помидоры морковка картошка молоко сметана" (без запятых потому что так отдает гугловский распознователь голоса)

После api.ai или шаблонов в функцию приходит только перечень: "помидоры морковка картошка молоко сметана".

Функция ищет совпадение в существующих продуктах, при совпадении меняет статус на "надо купить" . Если не находит то добавляет новый продукт с категорией "Неотсортированные", если такой круппы нет то добавляет ее.

Вроде как работает, но есть проблема с наличием в названиях прилагательных. Например:

"помидоры молоко лук репчатый белый хлеб"

Внимание Вопрос:

Как реализовать поиск совпадений в двух массивах где может быть последовательность прилагательного и существительного разные.
надиктовать можно как "хлеб белый" и "белый хлеб"

А также где в первом массиве это просто последовательные слова а не словосочетания: "помидоры, молоко, лук, репчатый, белый, хлеб"
А в массибе из бд словосочетания в случае наличия прилагательных "помидоры, молоко, лук репчатый, белый хлеб" или так "помидоры, молоко, репчатый лук, хлеб белый"

Узнать что очередное слово прилагательное или существительное поможет phpmorphy. А так же не разобрался как им пользоваться для более точного поиска совпадений . Например сказали "сметаны" а в базе "сметана", без морфи добавиться новый продукт.

Помогите в написании куска кода разбора массивов.
Как будет готово и будет работать нормально выложу.
За это сообщение автора lanket поблагодарил:
kawkay (Вт янв 23, 2018 3:34 pm)
Рейтинг: 1.16%
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Пн янв 22, 2018 12:34 pm

Да по сути кому интересно:
СпойлерПоказать

Код: Выделить всё

/**
* add To Shoping List From Voice
*
* @access public
*/
 function addToListFromVoice($voiceList) {
    $products = explode(" ", $voiceList);
    If (count($products) > 0) {
        $this->voice = True;
        foreach ($products as $product) {
            $srch = array();
            $srch['CODE'] = $product;
            $srch['IS_CODE'] = False;
            $this->search_products($srch);
            if (count($srch['RESULT']) > 0){
             $this->addToList($srch['RESULT'][0]['ID']);
            } Else {
             $srch['TITLE'] = "Неотсортированные";
             $this->search_product_categories($srch);
             if (count($srch['RESULT']) > 0){
              $srch['CATEGORY_ID'] = $srch['RESULT'][0]['ID'];
             } Else {
              $this->mode='update';
              $this->edit_product_categories($srch);
              $srch['CATEGORY_ID'] = $srch['CATIDADDED'];
             }
             $this->mode='add_product';
             $this->search_products($srch);
             $this->addToList($srch['RESULT'][0]['ID']);
            }
        }
    }
 }
 
За это сообщение автора lanket поблагодарили (всего 2):
skysilver (Пн янв 22, 2018 12:41 pm) • kawkay (Вт янв 23, 2018 3:34 pm)
Рейтинг: 2.33%
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Пт фев 16, 2018 12:15 am

Учитывая общую тенденцию к голосовым помощникам и голосовому управлению добавил функцию в этот модуль для интеграции с голосовыми командами.

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

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

Собственно добавил в модуль всего лишь одну функцию, остальной код остался неизменным:
СпойлерПоказать

Код: Выделить всё

/**
* add To Shoping List From Voice
*
* @access public
*/
 function addToListFromVoice($voiceList) {
    global $sortby;
    global $title;
     if(gg('debugEnabled') == 'Producty') $debugEnabled = 1;
     if($debugEnabled) debmes('Products incoming message:'. $voiceList);
    $products = explode(" ", $voiceList);
    if($debugEnabled) debmes('Products incoming count:'. count($products));
    If (count($products) > 0) {
        // $this->voice = True;
        foreach ($products as $product) {
            if(strlen($product) > 2)
            {
                if($debugEnabled) debmes('Products produkt:'. $product);
                $srch = array();
                $srch['CODE'] = $product;
                $srch['IS_CODE'] = False;
                $this->search_products($srch);
                if (count($srch['RESULT']) > 0){
                 $this->addToList($srch['RESULT'][0]['ID']);
                 if($debugEnabled) debmes('Products produkt '.$product.' found, ID:'. $srch['RESULT'][0]['ID']);
                }
                Else 
                {
                    if($debugEnabled) debmes('Products produkt '.$product.' not found, adding');
                     $sear = array();
                     $sortby = 'ID';
                     $title = "Неотсортированные";
                     // $sear['TITLE'] = "Неотсортированные";
                     $this->search_product_categories($sear);
                     if (count($sear) > 0){
                            if($debugEnabled) debmes('Products category exiting uncnoun');
                            $this->category_id = $sear['RESULT'][0]['ID'];
                            //$srch['CATEGORY_ID'] = $sear['RESULT'][0]['ID'];
                     } 
                     Else 
                     {
                            if($debugEnabled) debmes('Products creating uncnoun');
                            $this->mode='update';
                            $this->edit_product_categories($srch);
                            $this->category_id = $srch['CATIDADDED'];
                            //$srch['CATEGORY_ID'] = $srch['CATIDADDED'];
                            if($debugEnabled) debmes('Products produkt '.$product.' adding to created uncnoun');
                     }
                     $this->mode='update';
                     $this->tab=='';
                     $title = $product;
                     global $qty;
                     $qty = 1;
                     $addpr = array();
                     $this->edit_products($addpr, 0);
                     $this->addToList($addpr['ID']);
                     if($debugEnabled) debmes('Products produkt '.$product.' not found, added to category id '.$srch['CATEGORY_ID']);
                }
            }
        }
    }
 }
Суть и применение функции:

В шаблонах поведения делаем к примеру

Код: Выделить всё

(закончил.+?|заканчива.+?) ?продукты
При срабатывании:

Код: Выделить всё

say("Что именно закончилось из продуктов?",2);
контекст: В контексте выполнить при совпадении:

Код: Выделить всё

say("Добавляю ".$matches[1]." в список покупок.");
    include_once(DIR_MODULES . 'app_products/app_products.class.php');
    $prod = new app_products();
    $prod->addToListFromVoice($matches[1]);
В список покупок попадают все найденные продукты.
Если какой либо продукт не находиться, то он добавляется в категорию "Неотсортированные".
Ну и если такой категории нет, то она сначала создасться и тот новый продукт, которого доселе небыло, добавиться в нее.


По сути чего yе хватает для счастья, может кто доработает. Всего лишь 2 пункта:

Поиск происходит "дословно", другими словами если в продуктах есть "хлеб" а вы сказали надо купить "хлеба" то добавиться дубликат по смыслу но не по содержанию. Т.Е. в продуктах будет как "хлеб" так и "хлеба" . Как я понимаю такое поможет исключить phpmorphy

Ну и вторая, более заморочная хотелка, уже описывал недавно тут. Я про "хлеб белый" и "белый хлеб" к примеру. Опять же, как понимаю, phpmorphy поможет решить задачку.

Я так совсем много времени убью разбираться как это сделать.
За это сообщение автора lanket поблагодарили (всего 4):
skysilver (Пт фев 16, 2018 12:03 pm) • ILGAS (Пт фев 16, 2018 2:29 pm) • fandaymon (Сб фев 17, 2018 4:39 am) • alex.frost (Чт авг 16, 2018 11:18 am)
Рейтинг: 4.65%
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
fandaymon
Сообщения: 1553
Зарегистрирован: Сб янв 13, 2018 5:00 pm
Благодарил (а): 39 раз
Поблагодарили: 574 раза

Re: Модуль Продукты

Сообщение fandaymon » Пт фев 16, 2018 1:03 am

lanket писал(а): По сути чего yе хватает для счастья, может кто доработает. Всего лишь 2 пункта:

Поиск происходит "дословно", другими словами если в продуктах есть "хлеб" а вы сказали надо купить "хлеба" то добавиться дубликат по смыслу но не по содержанию. Т.Е. в продуктах будет как "хлеб" так и "хлеба" . Как я понимаю такое поможет исключить phpmorphy

Ну и вторая, более заморочная хотелка, уже описывал недавно тут. Я про "хлеб белый" и "белый хлеб" к примеру. Опять же, как понимаю, phpmorphy поможет решить задачку.

Я так совсем много времени убью разбираться как это сделать.
А если использовать отдельную табличку с названием продуктов? Первое поле - Продукт, Второе - Форма которая запишется в необходимые продукты? Ну типа
Белый хлеб Белый хлеб
Хлеб Белый Белый хлеб
Хлеба Белый хлеб

Пополнять её, когда произносится незнакомый продукт, а потом вручную корректировать при необходимости. Через какое-то время все продукты будут в таблице и можно будет сразу конвертировать все синонимы в одну форму
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Пт фев 16, 2018 8:19 am

fandaymon писал(а):
А если использовать отдельную табличку с названием продуктов? Первое поле - Продукт, Второе - Форма которая запишется в необходимые продукты? Ну типа
Белый хлеб Белый хлеб
Хлеб Белый Белый хлеб
Хлеба Белый хлеб

Пополнять её, когда произносится незнакомый продукт, а потом вручную корректировать при необходимости. Через какое-то время все продукты будут в таблице и можно будет сразу конвертировать все синонимы в одну форму
Спасибо за предложение.
Как вариант буду иметь ввиду, если с phpmorphy не получится.

Вариант с phpmorphy мне кажется более правильный что ли. Плюс по вашему пути придётся ещё и front end перелопачивать, а это для меня ещё сложнее.

Помимо этого надо не забывать что одно дело держать словоформы, другое дело обработать массив надиктованных слов без знаков припенания. То же хлеб Белый приходит в таком виде 'редиска сыр белый хлеб масло' или так например 'редиска сыр хлеб белый масло'. Во первых без phpmorphy не обойтись для определения прилагательного, во вторых все равно надо вылавливать двойные названия.

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

Поэтому думаю логика такая : всегда подсматриваем за следующим словом и проверяем не прилагательное ли оно.
Если нет, то обрабатывается как одинарное название продукта.
Если да то ищем текущее слово в сочетании со следующим прилагательным, и второе словосочетание это следующее прилагательное с следующим существительным после предлогательного, в случае если оно существитеное конечно. А то вдруг 'хлеб белый зелёный лук'.

Ну и если что то находиться или добавляется в неотсортированное то эти слова из словосочетаний помечаются флагом чтобы пропустить их когда цикл дойдёт до них.

А может не так уж заморочно.

С утра голова как-то лучше соображает.

Отправлено с моего Redmi Note 4 через Tapatalk
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Пт фев 16, 2018 8:31 am

Подумал немного.

А что делать с 'хлеб белый лук' если нет ни 'белый хлеб' ни 'белый лук'?

Наверное так и добавить 'хлеб белый лук' для последующего ручного редактирования.

Ещё Поймал на мысли себя.
'хлеб белый лук зелёный лук репчатый чёрный перец'

Пипец а перец ещё и может быть не просто чёрным да ещё и молотый, то есть с двумя прилагательными.

Может у кого голова лучше варит в программировании и заинтересован в таком функционале поможет.

Отправлено с моего Redmi Note 4 через Tapatalk
За это сообщение автора lanket поблагодарили (всего 2):
ILGAS (Пт фев 16, 2018 2:29 pm) • Shk (Пт мар 02, 2018 10:46 am)
Рейтинг: 2.33%
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Пт фев 16, 2018 4:13 pm

Продолжаю осваивать данный модуль. Появилось ряд вопросов.

1. Список покупок:
[spoiler] Изображение[/spoiler]
Я так понял клик по корзине это внесение и вычеркивание из списка покупок. Галочка это когда бродишь по магазину и отмечаешь что уже в карзине.

Напрашивается вопрос отметка в виде карзины как то сама потом сбрасывается?
Или надо вручную потом по всему списку кликать для вычеркивания из списка?
Напрашивается кнопка 'вычеркнуть купленное' - снятие отметки картина везде где установлена галочка.

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

2 Странная закладка со списком продуктов где количество =0
[spoiler]Изображение[/spoiler]
Видимо это отслеживание по текущему количеству. Не думаю что практично. Не думаю что каждый раз когда беру яблоко буду тыкать в телефон или сообщать голосом об этом ради того чтобы вычесть. Это же количество отображается в списке покупок. Из чего следует что если и отслеживать количество, то явно должны быть разные поля для текущего количества и количества сколько надо купить.

3 Просрочка
[spoiler]Изображение[/spoiler]
Думаю после того как продукт был отмечен в карзиной и галочкой, надо обновить дату окончания срока годности. Вручную лазать ради этого в каждый продукт неудобно.
Или я чего-то не знаю?

Отправлено с моего Redmi Note 4 через Tapatalk
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
fandaymon
Сообщения: 1553
Зарегистрирован: Сб янв 13, 2018 5:00 pm
Благодарил (а): 39 раз
Поблагодарили: 574 раза

Re: Модуль Продукты

Сообщение fandaymon » Сб фев 17, 2018 4:38 am

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

Код: Выделить всё

$command='череный молотый перец белого лука гель для душа';
require_once(ROOT . "lib/phpmorphy/common.php");
$opts = array(
 'storage' => PHPMORPHY_STORAGE_MEM,
 'predict_by_suffix' => true,
 'predict_by_db' => true,
 'graminfo_as_text' => true,
 );
$dir = ROOT . 'lib/phpmorphy/dicts';
$lang = 'ru_RU';
        try {
            $morphy = new phpMorphy($dir, $lang, $opts);
            $this->morphy =& $morphy;
        } catch (phpMorphy_Exception $e) {
            die('Error occured while creating phpMorphy instance: ' . PHP_EOL . $e);
        }
        $words = explode(' ', $command);
        $base_forms = array();
        $partsOfSpeech=array();
        $f_word=array();
       $totals = count($words);
        for ($is = 0; $is < $totals; $is++) {
            if (preg_match('/^(\d+)$/', $words[$is])) {
                $base_forms[$is] = array($words[$is]);
            } elseif (!preg_match('/[\(\)\+\.]/', $words[$is])) {
                $Word = mb_strtoupper($words[$is], 'UTF-8');
                $base_forms[$is] = $morphy->getBaseForm($Word);
                $partsOfSpeech[$is] = $morphy->getPartOfSpeech($Word);
                $f_word[$is] = $morphy->getGramInfo($Word);
                $base_forms[$is][]=$words[$is];
            } else {
                $base_forms[$is] = array($words[$is]);
            }
        }


for ($is = 0; $is < $totals; $is++) {

    if ($partsOfSpeech[$is][0]=='С') {
        if (($is+1)<$totals) {
            if ($partsOfSpeech[$is+1][0]=='С') {
                $product=$base_forms[$is][0];
            }
            elseif ($partsOfSpeech[$is+1][0]=='ПРЕДЛ') {
                $product=$base_forms[$is][0] . ' ' . $words[$is+1] . ' ' . $words[$is+2];
                $is=$is+2;
            }
             elseif ($partsOfSpeech[$is+1][0]=='П') {
                $product=$base_forms[$is][0] ;

            }

        }
        else {
                $product=$base_forms[$is][0];
        }
    }
    elseif ($partsOfSpeech[$is][0]=='П') {
        if (($is+1)<$totals) {
            if ($partsOfSpeech[$is+1][0]=='С') {

                if (count($base_forms[$is+1])>2){
                 // выбираем форму согласованную по роду
                 for ($k= 0; $k < count($f_word[$is][0][0]['grammems']); $k++) {
                  $gram=$f_word[$is][0][0]['grammems'][$k];
                  if ($gram=='МР' or $gram=='СР' or $gram=='ЖР') {
                   break;
                  }
                 }
                 $kkk=0;
                 for ($kk= 0; $kk < count($base_forms[$is+1])-1; $kk++) {

                  for ($k= 0; $k < count($f_word[$is+1][$kk][0]['grammems']); $k++) {
                    if ($gram==$f_word[$is+1][$kk][0]['grammems'][$k]) {
                     $kkk=1;
                     break;
                    }
                  }
                  if ($kkk==1) break;
                 }
                $product=$base_forms[$is][0] .' ' . $base_forms[$is+1][$kk] ;
                $is=$is+1; 
                 
                }
                 else {
                $product=$base_forms[$is][0] .' ' . $base_forms[$is+1][0] ;
                $is=$is+1; 
                } 
            }
            elseif ($partsOfSpeech[$is+1][0]=='П') {
                if (($is+2)<$totals) {
                    if ($partsOfSpeech[$is+2][0]=='С') {

                        if (count($base_forms[$is+2])>2){
                            // выбираем форму согласованную по роду
                            for ($k= 0; $k < count($f_word[$is][0][0]['grammems']); $k++) {
                                $gram=$f_word[$is][0][0]['grammems'][$k];
                                if ($gram=='МР' or $gram=='СР' or $gram=='ЖР') break;
                   
                            }
                 
                            $kkk=0;
                            for ($kk= 0; $kk < count($base_forms[$is+2])-1; $kk++) {

                                for ($k= 0; $k < count($f_word[$is+2][$kk][0]['grammems']); $k++) {
                                    if ($gram==$f_word[$is+2][$kk][0]['grammems'][$k]) {
                                        $kkk=1;
                                        break;
                                    }
                                }
                                if ($kkk==1) break;
                            }
                            $product=$base_forms[$is][0] .' ' . $base_forms[$is+1][0] . ' ' . $base_forms[$is+2][$kk] ;
                            $is=$is+2; 
                 
                        }
                        else {
                            $product=$base_forms[$is][0] .' ' . $base_forms[$is+1][0] .' ' . $base_forms[$is+2][0];
                            $is=$is+2; 
                        }
                    }
                    else {
                        $product=$base_forms[$is][0] .' ' . $base_forms[$is+1][0];
                        $is=$is+1;
                    }    
                }
                else {
                    $product=$base_forms[$is][0] .' ' . $base_forms[$is+1][0];
                    $is=$is+1;
                }    
            }                
                
                
            
            
            
        }
        else {
            $product=$base_forms[$is][0];
        }    
    }        

 echo $product . '<BR>';
} 
За это сообщение автора fandaymon поблагодарил:
lanket (Сб фев 17, 2018 9:32 am)
Рейтинг: 1.16%
Аватара пользователя
lanket
Сообщения: 1168
Зарегистрирован: Вт окт 14, 2014 11:27 pm
Откуда: Санкт-Петербург
Благодарил (а): 260 раз
Поблагодарили: 163 раза

Re: Модуль Продукты

Сообщение lanket » Сб фев 17, 2018 9:35 am

fandaymon писал(а):Немножко поразбирался с phpmorphy - написал функцию,...
Ох. Спасибо добрый человек.
Буду внедрять и пробовать.

На самом деле до голосовой надиктовки не пользовался. А с надиктовкой модуль перешёл в раздел мастхэв.
Многократно удобнее смсок от супруги. Очень рекомендую всем попробовать.

Отправлено с моего Redmi Note 4 через Tapatalk
Разработка голосового асистента для Мажордомо по любому ключевому слову.
:arrow: Обсужение
:arrow: gitHub 2й версии терминала
:arrow: GitHub модуля для МД
gitHub сырого модуля 2й версии
:arrow: Connect
Rasberry Pi 2, MDM, MySensors. И говорящий апельсин.
Ответить