Недавно я разработал партию резистивных сенсоров влажности почвы. В этой статье я расскажу, как подключить эти сенсоры к системе умного лома MajorDoMo и сделать информацию по влажности почвы комнатных растений удобной для использования.
Перед тем как перейти к настройке MajorDoMo я немного конкретизирую свои требования:
- Сервер должен делать пересчет показаний сервера в калиброванное значение влажности почвы, а также в упрощенные понятия «сухо», «влажно», «срочно полить».
- Подключение однотипных сенсоров к системе должно быть как можно менее трудозатратным.
- Показания всех сенсоров (влажности и состояния батареи) должны отображаться на одной экранной форме.
- Должна быть настроена система оповещений с конкретными рекомендациями и проблемами для всей системы контроля влажности почвы.
- При необходимости нужен отчет по частоте полива, дате последнего полива и прогнозу даты следующего полива
Сразу скажу, что последняя функция возможна только при накоплении данных за довольно длительный период и на момент написания статьи не реализована.
Подключение сенсоров к MajorDoMo
После включения контроллеров влажности новые ноды начинают появляться на страницы MajorDoMo Mysensors. В прошивке контроллера прописаны презентации двух сенсоров — значение влажности в виде значения АЦП и напряжение батареи питания, считанной через функцию ReadVcc()
Для удобства меняю названия нод на понятные мне
Наиболее близкий тип к сенсору влажности почвы из существующих это класс SHumSensors. Но в моем случае он будет отображать в качестве основного параметра влажности то что передается с контроллера, то есть значение АЦП. Пересчитывать эти значения в процентный показатель влажности я решил на стороне сервера, чтобы каждый раз при калибровке не лезть в прошивку контроллера. Поэтому я создал новый класс, наследующий SHumSensors с двумя новыми свойствами: «Относительная влажность почвы» и «Оценка влажности почвы»
Относительная влажность почвы указывается ка ключевое свойство с желаемым периодом хранения (в моем случае 1000 дней) в истории параметров (читай, в базе MySQL).
Свойство «Оценка влажности» у меня не ключевое и историю его хранить не нужно, что и указывается при создании
После этого я отредактировал существующий метод valueUpdated моего класса, который вызывается при каждом изменении свойства value, унаследованного из родительского класса.
В PHP код я пишу формулу пересчета показания АЦП в относительную влажность, полученную при калибровки сенсора и оценочное значение влажности, удобное для быстрого понимания
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$adc = $this->getProperty('value'); $new_value = 0.000001*$adc*$adc*$adc*-1; $new_value += $adc*$adc*0.001649; $new_value += $adc*-0.686978; $new_value += 121.559157; $new_value = round($new_value,1); $this->setProperty('RelativeHumSoil',$new_value); if( $new_value == '' || $new_value <= 0 ) $this->setProperty('RatingHumSoil','Нет данных'); else if( $new_value < 40 ) $this->setProperty('RatingHumSoil','Нужен полив'); else if( $new_value < 50 ) $this->setProperty('RatingHumSoil','Скоро полив'); else if( $new_value < 75 ) $this->setProperty('RatingHumSoil','В норме'); else $this->setProperty('RatingHumSoil','Очень влажно'); |
После этого можно создавать объекты нового класса для удобства идентификации в названии добавляя номер ноды Mysensors и прописывая в свойство Name название растения
Для параметра напряжения батареи каждого контроллера я не стал создавать нового класса, а взял готовый SVoltageSensors. Для удобства добавил ему свойство TextStatus и в метода valueUpdated добавил PHP код его формирующий
1 2 3 4 5 6 |
$val = $this->getProperty('value'); $min = $this->getProperty('minValue'); if( $val <= $min ) $this->setProperty('TextStatus','Низкий заряд батареи'); else $this->setProperty('TextStatus','Батарея в норме'); |
Теперь, заполнив свойство minValue, в TextStatus прописывает строка о состоянии батареи. На самом деле можно было воспользоваться встроенным механизмом контроля батареи Mysensors — посылать процент разряда батареи sendBatteryLevel(). Для этого нужно зашить внутрь контроллера тип батареи и диапазоны ее напряжения. На данном этапе проекта я решил обойтись вычислением уровня разряда на стороне сервера.
Итак, после того как для каждого контролера я сформировал пару объектов сенсором относительной влажности и сенсором батареи, я связал эти сенсоры с соответствующей нодой Mysensors
Форма контроля влажности почвы
Для отображения показания всех параметров влажности почвы и состояния батарей питания создаю отдельную сцену с одним единственным элементом типа HTML.
Сцена с кучей отдельных информеров или иконок смотрелась бы очень эффективно, но трудоемкость на ее создания, а также последующие добавления параметров мне показалась слишком высокой.
В HTML код элемента сцены прописываем HTML таблицу с выводом всех параметров контроллеров влажности
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
<table width=1000 border=1> <tr> <td width=250 height=160 valign=top align=left> <h4>[70] %SavSoil70.Name%</h4> Влажность: %SavSoil70.RelativeHumSoil% %<div id="pp2">(%SavSoil70.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage02.value% В <div id="pp2">(%MysensorsSensor_voltage02.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage02.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[71]</h4> </td> <td width=250 height=160 valign=top align=left> <h4>[72] %SavSoil72.Name%</h4> Влажность: %SavSoil72.RelativeHumSoil% %<div id="pp2">(%SavSoil72.RatingHumSoil%)</div> Температура: %MysensorsSensor_temp02.value% С<br><br> Батарея: %MysensorsSensor_voltage03.value% В <div id="pp2">(%MysensorsSensor_voltage03.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage03.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[73] %SavSoil73.Name%</h4> Влажность: %SavSoil73.RelativeHumSoil% %<div id="pp2">(%SavSoil73.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage04.value% В <div id="pp2">(%MysensorsSensor_voltage04.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage04.updatedText% <br> </td> </tr> <tr> <td width=250 height=160 valign=top align=left> <h4>[74] %SavSoil74.Name%</h4> Влажность: %SavSoil74.RelativeHumSoil% %<div id="pp2">(%SavSoil74.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage05.value% В <div id="pp2">(%MysensorsSensor_voltage05.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage05.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[75] %SavSoil75.Name%</h4> Влажность: %SavSoil75.RelativeHumSoil% %<div id="pp2">(%SavSoil75.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage06.value% В <div id="pp2">(%MysensorsSensor_voltage06.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage06.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[76] %SavSoil76.Name%</h4> Влажность: %SavSoil76.RelativeHumSoil% %<div id="pp2">(%SavSoil76.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage07.value% В <div id="pp2">(%MysensorsSensor_voltage07.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage07.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[77] %SavSoil77.Name%</h4> Влажность: %SavSoil77.RelativeHumSoil% %<div id="pp2">(%SavSoil77.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage08.value% В <div id="pp2">(%MysensorsSensor_voltage08.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage08.updatedText% <br> </td> </tr> <tr> <td width=250 height=160 valign=top align=left> <h4>[78] %SavSoil78.Name%</h4> Влажность: %SavSoil78.RelativeHumSoil% %<div id="pp2">(%SavSoil78.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage09.value% В <div id="pp2">(%MysensorsSensor_voltage09.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage09.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[79] %SavSoil79.Name%</h4> Влажность: %SavSoil79.RelativeHumSoil% %<div id="pp2">(%SavSoil79.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage10.value% В <div id="pp2">(%MysensorsSensor_voltage10.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage10.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[80] %SavSoil80.Name%</h4> Влажность: %SavSoil80.RelativeHumSoil% %<div id="pp2">(%SavSoil80.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage11.value% В <div id="pp2">(%MysensorsSensor_voltage11.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage11.updatedText% <br> </td> <td width=250 height=160 valign=top align=left> <h4>[81] %SavSoil81.Name%</h4> Влажность: %SavSoil81.RelativeHumSoil% %<div id="pp2">(%SavSoil81.RatingHumSoil%)</div> Батарея: %MysensorsSensor_voltage12.value% В <div id="pp2">(%MysensorsSensor_voltage12.TextStatus%)</div><br> Последний опрос: %MysensorsSensor_voltage12.updatedText% <br> </td> </tr> </table> |
В результате получаем такую вот форму
Для наблюдения изменения влажности можно использовать расширение MajorDoMo «Графики»
Здесь на графиках наглядно видно поливы трех растений.
Настройка оповещений
Типов оповещений в MajorDoMo великое множество — СМС, различные мессенджеры, социальные сети, а также встроенный помощник Алиса с голосовым выводом. Мне удобно получать уведомление утром на электронную почту.
Для формирования отчета электронным письмо я разработал сценарий с PHP кодом, выполняемый ежедневно утром:
Сценарий анализирует текущее состояние сенсоров и формирует сперва важные оповещения — список растений, которым требуется полив, списки контроллеров которым необходима замена батареи и которые не выходят на связь. Эти же проблемы передаются через помощника Алису. В конце письма добавляется полная сводка параметров контроллеров влажности на манер формы отображения
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
require_once 'lib/PHPMailer/PHPMailerAutoload.php'; $mail = new PHPMailer; $mail->setLanguage('ru', 'lib/PHPMailer/language/'); $mail->isSMTP(); //Enable SMTP debugging // 0 = off (for production use) // 1 = client messages // 2 = client and server messages $mail->SMTPDebug = 0; $mail->Debugoutput = 'html'; $mail->Host = 'smtp.yandex.com'; //Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission $mail->Port = 587; //Set the encryption system to use - ssl (deprecated) or tls $mail->SMTPSecure = 'tls'; $mail->SMTPAuth = true; $mail->CharSet = "UTF-8"; $mail->Username = 'Пользователь@yandex.ru'; $mail->Password ='Пароль'; $mail->setFrom('Пользователь@yandex.ru', 'SmartHome'); $mail->addAddress('Почтовый адрес 1', ''); $mail->addAddress('Почтовый адрес 2', ''); $subj='Ежедневный отчет по влажности почвы растений'; $mail->Subject = $subj; global $wat,$bat,$err,$body,$body1,$body2,$body3; $wat = 0; $bat = 0; $err = 0; $body = ''; $body1 = ''; $body2 = ''; $body3 = ''; ReportSoil1("[70]",'SavSoil70','MysensorsSensor_voltage02'); ReportSoil1("[72]",'SavSoil72','MysensorsSensor_voltage03'); ReportSoil1("[73]",'SavSoil73','MysensorsSensor_voltage04'); ReportSoil1("[74]",'SavSoil74','MysensorsSensor_voltage05'); ReportSoil1("[75]",'SavSoil75','MysensorsSensor_voltage06'); ReportSoil1("[76]",'SavSoil76','MysensorsSensor_voltage07'); ReportSoil1("[77]",'SavSoil77','MysensorsSensor_voltage08'); ReportSoil1("[78]",'SavSoil78','MysensorsSensor_voltage09'); ReportSoil1("[79]",'SavSoil79','MysensorsSensor_voltage10'); ReportSoil1("[80]",'SavSoil80','MysensorsSensor_voltage11'); ReportSoil1("[81]",'SavSoil81','MysensorsSensor_voltage12'); $body_all = 'Требуется полив: '.$wat.' '.$body1."\n\n\n"; $body_all = $body_all.'Батарея: '.$bat.' '.$body2."\n\n\n"; $body_all = $body_all.'Нет связи: '.$err.' '.$body3."\n\n\n"; $body_all = $body_all."Полный отчет:\n".$body ; if( $wat > 0 )say('Требуется полив: '.$wat.' '.$body1); if( $bat > 0 )say('Батарея: '.$bat.' '.$body2); if( $err > 0 )say('Нет связи: '.$err.' '.$body3); $mail->Body = $body_all; if (!$mail->send()) { say( "Ошибка почты: " . $mail->ErrorInfo); } else { say( "Отчет по влажности почты отправлен!"); } /** * Формирование отчета по одному сенсору */ function ReportSoil1($num,$soil,$vcc ){ global $body, $body1, $body2, $body3, $wat, $bat, $err; // Проверка необходимости полива if( gg($soil.'.RatingHumSoil') == 'Нужен полив' ){ if( $wat != 0 ) $body1 = $body1.', '; $body1 = $body1.gg($soil.'.Name'); $wat++; } // Проверка заряда батареи if( gg($vcc.'.TextStatus') == 'Низкий заряд батареи' ){ if( $bat != 0 ) $body2 = $body2.', '; $body2 = $body2.gg($soil.'.Name'); $bat++; } // Проверка что сенсор живой if( time() - gg($vcc.'.updated') > 18000 ){ if( $err != 0 ) $body3 = $body3.', '; $body3 = $body3.gg($soil.'.Name'); $err++; } // Заполнение основного отчета $body = $body."\n".$num.' '.gg($soil.'.Name').': '; $body = $body.gg($soil.'.RelativeHumSoil'); $body = $body.'% ('.gg($soil.'.RatingHumSoil').' )'; $body = $body.', бат:'.gg($vcc.'.value'); $body = $body.' ('.gg($vcc.'.TextStatus').' )'; $body = $body.', '.gg($vcc.'.updatedText'); } |
В результате работы сценария мне каждое утро приходит примерно такое письмо:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Требуется полив: 1 Молочай Батарея: 0 Нет связи: 2 Драцена, Плющ Полный отчет: [70] Пальма большая: 52.2% (В норме ), бат:3.61 (Батарея в норме ), 5 мин. назад [72] Драцена: 53.6% (В норме ), бат:3.73 (Батарея в норме ), 06.11.2018 04:07 [73] Монстера: 57.3% (В норме ), бат:3.87 (Батарея в норме ), 1 мин. назад [74] Хлорофитум (кухня): 42.6% (Скоро полив ), бат:2.91 (Батарея в норме ), 1 мин. назад [75] Молочай: 37.6% (Нужен полив ), бат:2.92 (Батарея в норме ), 4 мин. назад [76] Фикус Бенджамина: 62.5% (В норме ), бат:2.98 (Батарея в норме ), 1 мин. назад [77] Толстянка: 61.8% (В норме ), бат:3.04 (Батарея в норме ), 3 мин. назад [78] Плющ: 40.1% (Скоро полив ), бат:2.93 (Батарея в норме ), 22.12.2018 21:47 [79] Драцена красн.: 47.1% (Скоро полив ), бат:3.09 (Батарея в норме ), 31 сек. назад [80] Шеффлера: 88.1% (Очень влажно ), бат:2.90 (Батарея в норме ), 1 мин. назад [81] Циссус (виноград): 118.8% (Очень влажно ), бат:3.05 (Батарея в норме ), 1 мин. назад |
Небольшой итог
В прошлый раз я писал мониторинг влажности сенсоров на PHP и получил гораздо более скромные результаты, потратив намного больше времени. Мониторинг влажности в системе MajorDoMo мне нравится своими возможностями и гибкостью работы.
На момент написания статьи система работает уже пол года. В датчиках стоят самые дешевые щелочные батарейки из магазина Галамарт.
А я готовлюсь к весне запустить эту систему в теплице и открытом грунте на своем огороде с GSM-шлюзом Mysensors.
«..А я готовлюсь к весне запустить эту систему в теплице и открытом грунте на своем огороде с GSM-шлюзом.»
Запустили?
Нет еще
Там снега еще по колено
В майские начну заниматься.
«… А я готовлюсь к весне запустить эту систему в теплице и открытом грунте на своем огороде с GSM-шлюзом Mysensors»
Как успехи?
Про GSM-шлюз можно подробнее? Какой использовался? Отсюда: https://forum.mysensors.org/topic/9147/my_gateway_tinygsm/2 или другой?
Пока еще не запустил
Отлаживаю исполнительные механизмы — полив, наполнение емкости с водой, открытие форточек.
На шлюз скорее всего поставлю Orange PI с USB-модемом. Так больше функционал (можно, например, еще и камеры поставить)
Я не совсем понял как передается информация на мажордомо? Передатчики есть, их много, как инфа обрабатывается, кем?
Хотелось бы заказать у вас комплект с несколькими датчиками il@li.ru