Компьютеризация насосной

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

И если с первым было все более-менее нормально – были протянуты провода от двух реле и от пускателя в соседнее помещение, подключены к USB-реле, а то, в свою очередь, воткнуто в одноплатник, то с измерителем вышла загвоздка. Размещен он был в щитке для насоса, а его rs232-интерфейс через витую пару, протянутую в соседнее помещение, был подключен к переходнику на pl2303. Наводки внутри щитка, а также на линии зачастую приводили к зависанию то ли измерителя, то ли переходника. Кончилось все тем, что один переходник вылетел. Поменял на другой – того хватило ровно на один запуск насоса. Возможно, если использовать не UTP, а FTP для передачи данных, это немного спасло бы ситуацию, но еще в голове сидела мысль о том, что хотелось бы больше возможностей по контролю насосной, а линий не хватает. Было решено двигаться в сторону установки отдельного одноплатника прямо возле щитка.

Ну а тут уж фантазии было где развернуться 🙂

Прежде всего, купил с рук Raspberry Pi первого поколения. По цене выходила как RPi Zero, но имела нормальные USB-разъемы (т.е., не нужен хаб) и сетевую карту (т.е., не надо ставить отдельную через еще один USB-разъем). Смущало то, что в моей ревизии было только 2 USB-порта – вроде как мало. Как оказалось, зря.

В начале хотелось просто пересобрать имеющееся железо вокруг нового одноплатника – поставить USB-реле на большее число каналов, подключить измеритель сети через pl’ку. Но хотелось еще иметь контроль состояния реле давления насоса, да и нужно ли USB-реле (хоть и опробованное ранее и успешно работающее), если есть гребенка GPIO – которой я, правда, до того ни разу не пользовался. Решил исследовать новую для себя тему.

Примерно прикинул необходимые возможности компьютера, число входов/выходов – и в итоге заказал несколько разных релейных модулей с опторазвязкой. Попутно собрал схему на оптопарах по мотивам этого поста на 4 канала. Изначальный вариант в точности повторял схему из раздела “Опторазвязка”, лишь на двух входах, оба из которых должны были контролировать реле давления, решил сэкономить на 1N4007 и сделать его общим – у реле все равно есть общий провод.

По входам/выходам получалось, что нужно 6 выходов:

  1. Переключение между реле давления
  2. Блокировка работы насоса
  3. Принудительный пуск насоса
  4. Управление подсветкой бассейна
  5. Переключение режимов “таймер/ручной” у фильтра бассейна
  6. Управление “включить/выключить” в ручном режиме у фильтра

…и 4 входа:

  1. Реле давления обычное
  2. Реле давления подкачки
  3. Состояние фильтра
  4. И раз уж контролировать – так контролировать: рядом есть “Зубр 3F”, можно сигнализировать о наличии всех трех фаз.

Ко всему прочему надо было обеспечить аварийный пуск насоса (когда давление в системе 0) в обход реле – и, с другой стороны, при возможном подвисании компьютера обойти ситуацию, когда насос начнет работать без остановок. Планировалось с малинки управлять таймером, который включал бы реле принудительного запуска, например, ровно на минуту. Но хорошо бы обеспечить “железный” вариант защиты от превышения давления. Хотел уже ставить 3-е реле давления – в общем, вовремя остановился. Зачем городить огород, если можно просто поменять второе реле на реле БЕЗ защиты от сухого хода? Надо подкачать воду – переключились на него. Надо пустить насос с нуля – переключились на него. И никаких таймеров.

В итоге заменил реле давления, попутно освободился один канал у реле управления.

В процессе исследования возможностей работы с gpio остановился на пакете wiringpi, в составе которого есть утилита gpio. С выходами разобрался быстро – правда, как выяснилось, заказал немного не те реле: купил с управлением по низкому уровню (подтягиваем сигнал к нулю – реле включается), что могло стать проблемой, если при загрузке до инициализации GPIO на контактах низкий уровень. Опасался зря, до инициализации выводы в подвешенном состоянии – слабенький ток через опторазвязку на релейных модулях шел (светодиоды индикации состояния чуть светились), но к срабатыванию реле это не приводило. А при инициализации можно было сразу указать нужное состояние. Добавил такое в /etc/rc.local:

gpio export 22 high
gpio export 23 high
gpio export 24 high
gpio export 25 high
gpio export 18 high
gpio export 27 high

Дальше можно управлять реле теми же командами, например, “gpio export 22 low” для включения реле.

Со входами было чуть интереснее. С резистором 4.7 КОм транзистор внутри оптопары почему-то не мог притянуть выход схемы к земле. Начал играть с внутренними, софтово управляемыми резисторами подтяжки на малинке – началась обратная ситуация – не мог их “передавить” внешним управлением. Решил чуть изменить схему – коллектор оптопары прицепил на +3.3V, эмиттер – на вход малинки. Так даже логичнее было бы: есть 220В на входе схемы – есть “1” на входе малинки. Стало чуть лучше, но – не до конца. При “нуле” вход болтался и небольшие уровни напряжения вызывали срабатывание: малинка иногда детектила “0” как “1”. Подтянул вывод малинки через резистор на 60 с лишним КОм к земле. Ложные срабатывания пропали – началась проблема с “единицей”. Тут наконец-то дошло, что малинка просто ловит полупериоды сети и какой-то из моментов замера попадает на “отсутствие” входного сигнала. Вышел из положения, добавив конденсаторы по 0.22 мкФ между входом малинки и общим. Возможно, это помогло бы и раньше, но уже не стал возвращаться к старой схеме.

Для конфигурирования входов в том же /etc/rc.local добавил

gpio export 7 in
gpio export 8 in
gpio export 9 in
gpio export 10 in

gpio -g mode 7 tri
gpio -g mode 8 tri
gpio -g mode 9 tri
gpio -g mode 10 tri

Во втором блоке не стоит забывать ключ “-g” – как оказалось, при вызове разных операций может использоваться разная нумерация GPIO. Либо можно просто использовать этот ключ везде.

Прочитать состояние входа можно через ту же утилиту gpio:

gpio -g read 9

Дальше – больше. Зачем использовать pl2303 для организации rs232, когда на малинке есть штатно один последовательный порт? Правда, дефолтно в Raspbian задействованный под консоль, поэтому запускаем raspi-config, идем в “Interface Options” -> “Serial Port” и отключаем консоль на последовательном порту. Теперь можно задействовать 8 и 10 пин малинки для прямого подключения измерителя PZEM-004t, в системе он видится как /dev/serial0. В том же разделе заходим в пункт “1-Wire” и включаем поддержку данного протокола – теперь на 7-й вывод можно прицепить копеечный термодатчик DS18B20 и контролировать температуру, например, в помещении через файл /sys/bus/w1/devices/*/temperature.

Немного о подключении. На гребенке есть 2 контакта +5В – они у меня ушли на 2 релейных модуля – на 2 и 4 реле. 2 контакта с 3.3V использованы на данный момент для питания PZEM-004t, DS18B20 и опторазвязки входов. Выход DS18B20 через резистор 4.7 КОм подтягивается к тем же +3.3V; PZEM-004t требует небольшой доработки: на верхней (если разместить разъем данных слева) оптопаре надо параллельно штатному резистору на 1 КОм припаять еще один такой же – это позволит работать измерителю на 3.3V.

PZEM-004t в моем случае требовал еще одной доработки. Так как в моем случае используется запитка скважинного насоса от двух фаз, а измерять 380V PZEM-004t не может, остается мерять сеть на выходе трансформатора – которая, в свою очередь, появляется только в момент работы скважины. А так как контроллер на измерителе питался от той же сети, то, выходит, измеритель становился доступным в системе исключительно в момент работы насоса, что очень неудобно. Было решено развязать цепь питания измерителя и измеряемую сеть.

Штатная схема питания выглядит так:

Для доработки отпаиваем один вывод конденсатора балласта (желтый) – тот, который возле клемм подключения сети к измерителю. Последовательно с ним цепляем еще один, примерно того же номинала. И параллельно этой цепочке ставим резистор килоом на 750. На получившуюся точку и подаем теперь 380V. Резистор на 470 КОм на плате убираем (я просто обрезал дорожку).

Итог того, что получилось:

И в процессе сборки:Финальный вариант:

Для запитки малинки использован DC-DC-преобразователь на mp2307 (использующийся в KIS-3R33), питание по двум свободным парам витой пары. USB в итоге не использовался вообще. Свободными остались контакты с шиной i2c и 2 GPIO – исходя из этого хочу добавить 2 кнопки и небольшой дисплей, о чем допишу позже.

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

Для контроля входов, как выяснилось, inotify неприменим. Попробовал проект gpio-notify – почему-то тот иногда выдавал ложные значения – причем, при контроле нескольких файлов мог написать, что реакция произошла в другом файле, а не в том, где было изменение. Так или иначе, пока что написал простой скрипт, который в цикле проверяет состояние файлов, пишет его в переменные, если значение поменялось – выполняет команду. При периоде в 0.5 сек потребляет пару процентов процессорного времени, но пока хоть так. Можно будет еще попробовать сделать что-то на базе triggerhappy, раз уж он был в системе. Еще для пробы: pikeyd.

Итак, апдейт по дисплею и финальная сборка.

В качестве дисплея мне очень приглянулись OLED-дисплеи на контроллере SSD1306, подключаемые по I2C (которая, как уже писал выше, у меня как раз оставалась незадействованной). Стоимость около 3$ в местном магазине, растр с разрешением 128х64 точки, хорошая читаемость, простота подключения – почему бы и не попробовать?

Оставшиеся свободные GPIO – 11 и 17 – решил задействовать под 2 кнопки на панели компьютера.

Долго искал удобные для себя возможности использования дисплея из linux-shell’а, но ничего толкового так и не попалось. Большинство реализаций были на Python, с которым я не был знаком, часть из них так и не запустилась. Найденные одна или две реализации в виде полноценных утилит, которые можно использовать в шелле, тоже не заработали. Искал возможность завести дисплей через lcd4linux, с которым я уже имел дело, когда подключал HD44780 к самодельному плееру, но примеров по работе с SSD1306 к нему не нашлось (хотя, как минимум, там была работа с I2C).

Одним из найденных примеров на Python было весьма дружелюбное руководство по использованию таких дисплеев – на базе него и начал вникать в незнакомую мне тему. Вначале думал как-нибудь сделать интерфейс к шеллу, а дальше уже привычным для себя способом сделать всю обвязку вокруг индикатора, но играясь с простейшим примером из руководства выше, выстраивая layout и добавляя логику в скрипт, начал постепенно вникать в синтаксис и развивать скрипт. Новые для себя моменты (да и даже привычные, просто в новом синтаксисе) гуглил. Итог – скрипт на 9 КБ, где реализована работа с дисплеем, отслеживание состояния входов, реле, вывод данных с термодатчика и ваттметра, работа с кнопками на панели, а также логирование событий (иначе говоря, логика шелл-скрипта, о котором писал выше, была тоже написана в рамках этого Python-скрипта).

Для работы скрипта нужно установить oled-text:

apt-get install python3-pip python3-pil

Насчет нужности второго пакета в моем случае на сейчас не уверен (картинки-то не выводим), но на всякий случай дописал.

Ну и установка самого oled-text:

pip3 install oled-text

Собственно, сам скрипт

Из интересных моментов:

  • SmallLine и BigLine из руководства штатно отличаются только шрифтом
  • Честно говоря, до сих пор не знаю, как при необходимости задать адрес дисплея. oled-text использует тот, что совпал с моим – на том и остановился. А в целом, найди дисплеи на шине можно через i2cdetect из пакета i2c-tools
  • Не нашел возможности задать яркость дисплея. Пишут, что OLED со временем (несколько лет) выгорает, так что можно было бы реализовать затемнение экрана при отсутствии событий. Но пока так. В худшем случае через несколько лет заменю экран. Можно, конечно, гасить его полностью через oled.clear(), но это не сильно удобно.
  • Непривычной / нелогичной была необходимость открывать каждый раз файл GPIO для чтения. Казалось бы, открыл раз и перечитывай его потом, получая новые данные.
  • На Raspberry Pi ощутимо дольше перерисовывался экран по oled.show() по сравнению с Orange Pi, где я тестировал скрипт перед “боевым” использованием. В итоге функция отрисовки выполняется в фоне, отдельным тредом. Вроде как тред надо закрывать через display.join(), однако это вызывало ожидание его завершения – т.е., упирались в ту же паузу, что и без отдельного треда.
  • На сейчас основная задержка скрипта – это вычитка термодатчика, около 0.9c. Можно сделать через прослойку, как это сейчас сделано с ваттметром (там значение читается скриптом, который отдает данные для rrdtool и параллельно кладется в файл /home/rain/out_power), но правильнее было бы научиться пускать задачу отдельным тредом в фоне, получая результаты из нее в основном скрипте. При этом цикл основного скрипта может быть в 2-3 раза меньше, чем вычитка данных с датчика.

Логика работы с кнопками – не особо элегантная и завязана на внутренний цикл скрипта (т.е., все вот эти задержки из-за опроса термодатчика и все остальное) – т.е., несмотря на sleep(0.25) в конце, реальный цикл выходит чуть больше секунды. Соответственно, для срабатывания кнопки ее нужно удерживать дольше этого времени. Всего функций 4:

  • Короткие нажатия кнопки 1 – перебор режимов фильтра: авто/выключен/включен
  • Длинное нажатие кнопки 1 – включение/выключение подсветки бассейна
  • Короткие нажатия кнопки 2 – переключение между реле давления насоса
  • Длинное нажатие кнопки 2 – разовая подкачка. Если сейчас реле подкачки во включенном состоянии, то переключаемся на него (может стоит добавить проверку, не включены ли мы уже на него в качестве штатного режима? Хотя такая ситуация маловероятная), докачиваем воду до срабатывания реле, после чего переключаемся на нормальное реле.

На пока все. Скрипт пускается из cron’а:

* * * * * pgrep -x display-rpi.py 1>/dev/null || /home/rain/bin/display-rpi.py

Почему-то на pidof иногда были ложные сработки и скрипт запускался дважды.

Update: случайно открыл для себя, что время вычитки данных из DS18B20 зависит от разрешения:

9-bit — 93.75 ms (0,5 градуса)
10-bit — 187.5 ms (0,25)
11-bit — 375 ms (0,125)
12-bit — 750 ms (0,0625)

Разрешения в 10 бит вполне достаточно для мониторинга температуры в помещении, а время замера (а значит – и время цикла скрипта) сокращается основательно. Добавил такое в /etc/rc.local:

echo 10 > /sys/bus/w1/devices/28-0301a279404b/resolution

Update: в конце 2023 окончательно избавился от данного проекта, заменив все на пару отдельных блоков на ESP32 с интеграцией в Home Assistant. Веб-интерфейс тут так и не сделал; команды (изредка) дергал через SSH, в остальном – компик был вещью в себе и автоматизации делались вызовом нужных команд из cron’а.

Для истории – схема подключений насосной части в щитке:

 

Фактически, такой же она осталась и для варианта на микроконтроллере – по факту поменял местами только цвет проводов в кабеле, идущего со щитка, ну и на сейчас реальный ноль используется в том числе для питания БП микроконтроллера (для малинки использовалось питание по витой паре).

3 мысли о “Компьютеризация насосной”

Добавить комментарий