Итак я наклепал кучу контроллеров с MySensors и подключил их к MajorDoMo через шлюз. Данная статья о том как с этим жить дальше. Ведь для подключения к MajorDoMo с каждым устройством приходится выполнять немало действий: создание объектов и подключение их к сенсорам Mysensors, настройка обработки приходящих значений, отображение показаний на экранных формах (планах, сценах), формирования отчетов по показаниям датчиков.
Для подключения устройств Mysensor к MajorDoMo я вижу два пути:
- Максимально воспользоваться тем что есть. То есть прицепить все сенсоры, которые подключились к системе, к существующим классам системы, а далее цеплять их к сценам, формам, графикам и сценариям.
- Создать свою иерархию классов , соответствующих моим устройствам, максимально заложить в них логику работы и отображения данных и уже цеплять все подключившиеся сенсоры к ним.
До сих пор я максимально шел по первому пути, разве что немного расширял существующие классы. В результате я получил огромное количество однотипных объектов (ведь каждому сенсору моего устройства, которых у меня получается от 2 до 10, нужно создать отдельный объект соответствующего класса)
Кончилось все это переустановкой MajorDoMo (почему то при вызове сцен стал подвисать Apache c 100% загрузкой процессора), и вместе с этим я решил навести порядок в классах.
Задача
Требуется максимально упростить подключение большого количества однотипных датчиков влажности почвы. Все датчики имеют батарейное питание и выдают три параметра. Напряжение батареи, значение АЦП, которое может быть пересчитано во влажность почвы и температуру от отдельного сенсора DS18B20, который может быть установлен в устройстве.
Подготовительный этап. Создание базовых классов
Для начала создадим базовый класс SMyVccDevices для всех моих устройств с батарейным питанием.
Далее создаю общие свойства для всех батарейных устройств:
- Name — имя устройства, которое будет отображаться в отчетах и формах
- Vcc — напряжение питания, В — ключевое значение с хранением истории в базе
- VccMin и VccMax — значения необходимые для вычисления состояния батареи
- VccText — тестовое сообщение о состоянии батареи
Далее создадим метод vccUpdated, который будет срабатывать при каждом изменении свойства Vcc
Данный метод вычисляет напряжение батареи в процентах, формирует строку состояния батареи из записывает в VccText, а также пишет текущее время в свойство updated и запускает метод родительского класса setUpdatedText
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Изменяем время $this->setProperty('updated', time()); $this->callMethodSafe('setUpdatedText'); // Считываем значения $min = $this->getProperty('VccMin'); if( $min == '' || $min <=0 )$min = 2; $max = $this->getProperty('VccMax'); if( $max == '' || $max <=0 )$max = 3; $vcc = $this->getProperty('Vcc'); // Рассчитываем вольтаж в процентах $proc = 0; if( $vcc > $max )$proc = 100; else if( $vcc < $min )$proc = 0; else if( $min == $max )$proc = 0; else $proc = ($vcc - $min)/($max - $min)*100; // Пишем состояние батареи if( $proc > 50 )$text = 'Батарея в норме'; else if( $proc > 10 )$text = 'Низкий заряд батареи'; else $text = 'Критический заряд батареи'; // Пишем значение свойств $this->setProperty('VccText',$text); |
Класс SMyVccDevices готов. Теперь можно создавать классы конкретных устройств наследуя данный класс. Следующим создадим класс устройств измерения температуры влажности SMyTempHumDevices. Выделения этого класса может пригодиться для датчиков с DHT22, HTU21D и прочимих термо-гигрометров.
У данного класса создадим два ключевых свойства с хранением истории значений:
- Temp — температура
- Hum — относительная влажность
Собственных методов у данного класса нету
Создание класса моего устройства
Теперь собственно класс для резистивных устройств измерения относительной влажности почвы.
У него будет два дополнительных свойства:
- HumADC — значения АЦП контроллера, которое будем привязывать к непосредственно сенсор
- HymText — текстовое поле оценки влажности для отчетов и форм
И метод humUpdated, привязанный к изменению свойства HumADC. Алгоритм пересчета значений я оставлю прежним
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$adc = $this->getProperty('HumADC'); $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); if( $new_value > 100 )$new_value = 100; $this->setProperty('Hum',$new_value); if( $new_value == '' || $new_value <= 0 ) $this->setProperty('HumText','Нет данных'); else if( $new_value < 40 ) $this->setProperty('HumText','Нужен полив'); else if( $new_value < 50 ) $this->setProperty('HumText','Скоро полив'); else if( $new_value < 75 ) $this->setProperty('HumText','В норме'); else $this->setProperty('HumText','Очень влажно'); |
Для данного класса создадим шаблон отображения — вид, каким объекты данного класса будут выводиться на планах и сценах MajorDoMo
Мне удобнее табличный вид отображения всех значений в одну строчку
1 2 3 4 5 6 7 8 9 10 11 |
<table border=1 width=1000> <tr> <td width=30%><b>%.Name%</b></td> <td width=12%><img src="/cms/scenes/styles/common/i_temp.png">%.Temp%</td> <td width=12%><img src="/cms/scenes/styles/common/i_humidity.png">%.Hum%</td> <td width=12%><img src="/cms/scenes/styles/common/i_power.png">%.Vcc%</td> <td width=16%>%.HumText%</td> <td width=18%>Опрос: %.updatedText%</td> </tr> </table> |
Вот и все. Теперь нужно создать необходимое количество объектов класса SMyRSoilDevices
и вручную заполнить у них свойства Name, VccMin и VccMax
Осталось связать устройства MySensors с созданными объектами
Для создания сцены со всеми датчиками влажности достаточно накидать элементов типа «объект» и выбрать созданные объекты
Ну и для удобства создадим скрипт отправляющий отчет о влажности на электронную почту:
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 = 'Пользователь'; $mail->Password ='Пароль'; $mail->setFrom('От кого', 'SmartHome'); $mail->addAddress('Адрес', ''); $subj='Ежедневный отчет по влажности почвы растений'; $mail->Subject = $subj; global $wat,$bat,$err,$body,$body1,$body2,$body3; $wat = 0; $bat = 0; $err = 0; $body = ''; $body1 = ''; $body2 = ''; $body3 = ''; ReportSoil1('Soil72'); ReportSoil1('Soil73'); ReportSoil1('Soil74'); ReportSoil1('Soil75'); ReportSoil1('Soil76'); ReportSoil1('Soil77'); ReportSoil1('Soil78'); ReportSoil1('Soil79'); ReportSoil1('Soil80'); ReportSoil1('Soil81'); $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($soil){ global $body, $body1, $body2, $body3, $wat, $bat, $err; // Проверка необходимости полива if( gg($soil.'.HumText') == 'Нужен полив' ){ if( $wat != 0 ) $body1 = $body1.', '; $body1 = $body1.gg($soil.'.Name'); $wat++; } // Проверка заряда батареи if( gg($soil.'.VccText') == 'Критический заряд батареи' ){ if( $bat != 0 ) $body2 = $body2.', '; $body2 = $body2.gg($soil.'.Name'); $bat++; } // Проверка что сенсор живой if( time() - gg($soil.'.updated') > 18000 ){ if( $err != 0 ) $body3 = $body3.', '; $body3 = $body3.gg($soil.'.Name'); $err++; } // Заполнение основного отчета $body = $body."\n".gg($soil.'.Name').': '; $body = $body.gg($soil.'.Hum'); $body = $body.'% ('.gg($soil.'.HumText').' )'; $body = $body.', бат:'.gg($soil.'.Vcc'); $body = $body.' ('.gg($soil.'.VccText').' )'; $body = $body.', '.gg($soil.'.updatedText'); } |
В результате выполнения данного скрипта ежедневно на почту приходит такой отчет
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Требуется полив: 1 [74] Хлорофитум (кухня) Батарея: 0 Нет связи: 1 [72] Драцена Полный отчет: [72] Драцена: % ( ), бат: ( ), [73] Монстера: 63.9% (В норме ), бат:3.79 (Низкий заряд батареи ), 4 мин. назад [74] Хлорофитум (кухня): 37.6% (Нужен полив ), бат:2.85 (Батарея в норме ), 1 мин. назад [75] Молочай: 100% (Очень влажно ), бат:2.91 (Батарея в норме ), 02:31 [76] Фикус Бенджамина: 100% (Очень влажно ), бат:2.89 (Батарея в норме ), 2 мин. назад [77] Толстянка: 69.5% (В норме ), бат:2.95 (Батарея в норме ), 4 мин. назад [78] Плющ: 78% (Очень влажно ), бат:2.41 (Низкий заряд батареи ), 51 сек. назад [79] Драцена (красная): 81.7% (Очень влажно ), бат:3.01 (Батарея в норме ), 4 мин. назад [80] Шеффлера: 100% (Очень влажно ), бат:2.79 (Батарея в норме ), 4 мин. назад [81] Циссус (виноград): 88.1% (Очень влажно ), бат:2.97 (Батарея в норме ), 2 мин. назад |
Данная статья написана больше как памятка самому себе, но если кому то поможет разобраться, буду очень рад