Контроль заполнения бассейна
Система для мониторинга уровня воды, температуры, pH, ОВП, давление фильтра, использование электроэнергии и работа насоса. При необходимости доливает бассейн.
История
Идея
Летом 2015 года мы с сыновьями полностью перестроили нашу систему бассейнов. Все началось с проблемы с водяными линиями и клапанами, которые мы унаследовали, когда мы получили дом, проблем с фильтрами и в основном неумелой компании по производству бассейнов, которая была пережитком с того момента, когда мы получили дом. Когда это стало выглядеть так, я решил, что пора что-то сделать:
Наша собственная частная лагуна
Начало работы
Первым приоритетом было очистить пул, а затем выяснить, как сохранить его в таком состоянии. Мне всегда нравилась автоматизация, и я решил, что это идеальное место, чтобы попробовать ее. Вскоре бассейн снова выглядел так:
Вернуться к нормальному состоянию
Но проблема все еще оставалась в том, что всей системе не хватало как возможностей, так и интеллекта, и я хотел это изменить. Итак, первым делом нам нужно было заменить фильтр, помпу и кучу клапанов. Я провел много времени на веб-сайте Trouble Free Pool, и это было спасением для мастера по ремонту.
Моя рабочая сила
Мы столкнулись с несколькими неудачами, одна из которых была, когда они установили забор, они залили бетон вокруг линий, идущих от системы фильтров к бассейну.
Излишне говорить, что весь этот бетон и эти линии пула пришлось заменить, чтобы проект двинулся вперед. Практически все должно было уйти.
Вначале я решил добавить некоторую автоматизацию в новую систему пулов. Я выбрал систему управления под названием Автопилот. ( Моя семья говорит, что я выбрал его, потому что я пилот, и мне понравилось это имя! Эта система позволила бы мне преобразовать бассейн в бассейн с соленой водой и взять на себя часть управления, в основном, при необходимости, запустить генератор соленой воды и перекачивать кислоту для регулирования pH. Никакой другой автоматизации, кроме этих вещей, не было.
В конце концов мы все выяснили. Также нам вернули кухню, которая стала моей мастерской для проекта.
Готово:
Автоматизация - начало
Теперь, когда физическая установка была установлена и введена в эксплуатацию, я подумал, что было бы неплохо иметь возможность заполнять бассейн, не вынимая все время из шланга. Я подумал, что с Raspberry Pi и обычным спринклерным клапаном я буду в деле! Я купил еще один Pi (я использую их повсюду для различных проектов) и выложил то, что я хотел, чтобы он делал.
Raspberry Pi3
Изначально я полагал, что мне нужно уметь делать две вещи:
- Способ измерения уровня воды
- Способ наполнить бассейн, когда вода станет низкой.
Я начал проводить исследования и пришел к компании, которая производила жидкую рулетку, сопротивление которой менялось при повышении или понижении уровня воды (или другой жидкости). Milone с радостью создаст для меня юнит определенного размера, поскольку ни один из их размеров не подошел бы там, где я хотел бы его разместить.
Электронная лента от Milone
ОБНОВЛЕНИЕ :К сожалению, по какой-то причине мой Milone eTape пострадал от попадания воды внутрь самой оболочки и вышел из строя. Обсудив этот вопрос с Milone, я решил, что стоимость его замены и, возможно, возникнет такая же проблема, не стоит затрат на замену. Что еще хуже, мне нужен особый размер, который они должны сделать специально для меня.
Вода во внутреннем рукаве вызвала сбой ленты eTape….
Итак, мне понадобился другой способ измерить уровень моего бассейна, и я решил использовать один из них:
Поплавковый выключатель датчика уровня воды в баке из нержавеющей стали Elecall
Поскольку разница между моим низким уровнем воды и моим нормальным уровнем воды составляет около трех дюймов, это отлично сработало для меня. Мне просто нужно было придумать, как его смонтировать и заставить работать правильно.
Так как я знаю нескольких других людей, использующих eTape с отличными результатами, я собираюсь оставить все, что касается eTape, в моем проекте и добавить к нему способ, которым я делал настройку двойного поплавка. Таким образом, люди смогут увидеть несколько разных вариантов.
Поскольку он должен был быть расположен через двор от того места, где будет находиться мой Pi, необходимо было подключить его к собственному устройству для отчетности. Поскольку для этого мне не требовался Pi, я выбрал маломощный беспроводной клон Arduino с батарейным питанием, который передавал бы информацию обратно в существующую систему, которая у меня уже была в доме.
Эти устройства я приобрел в лабораториях Low Power Labs. В итоге я использовал четыре из них в своем проекте:один для уровня воды, один для температуры воды и два в основной системе для отслеживания комбинации температуры внутри корпуса, давления фильтра и использования воды.
Moteino R5-USB со вспышкой и приемопередатчиком RFM69HW 433 МГц
Эти клоны Arduino потребляют очень мало энергии - всего ~ 7 мкА в режиме глубокого сна, что означает, что они будут работать очень и очень долго от двух батареек AA. Датчик температуры воды плавает вокруг бассейна, а датчик уровня находится далеко от источника питания, поэтому мне пришлось использовать беспроводное оборудование с батарейным питанием.
Изначально у меня не было намерения делать что-либо, кроме автоматического добавления воды в бассейн, но, поскольку это часто происходит, проект рос своим собственным умом. Со временем я смогу сделать следующее:
- Следите за уровнем воды и при необходимости доливайте воду.
- Следите за температурой бассейна.
- Следите за давлением в фильтре.
- Монитор pH
- Монитор ОВП
- Отслеживайте потребление энергии, чтобы определить, работает ли насос бассейна.
- Следите за моей спринклерной системой, чтобы увидеть, работают ли спринклеры.
- Уведомлять меня, когда система запускается или добавляет воду (через Pushbullet, электронную почту или SMS).
- Оповестить меня, когда система перестанет добавлять воду.
- Сообщите мне, если в системе возникнет ошибка.
- Добавьте воду вручную через интерфейс командной строки или нажав кнопку на корпусе.
- Предоставьте чистый веб-интерфейс, чтобы видеть состояние системы и позволить мне запускать и останавливать заполнение пула через Интернет.
- Взаимодействовать с моей системой управления бассейном через Alexa (получать информацию и запускать / останавливать воду)
Наполнение бассейна
Независимо от того, что запускает маршрутизацию заполнения бассейна (вручную или автоматически), у меня должен был быть способ залить воду в бассейн. Поскольку от нас уже требуется установить вакуумный выключатель между системой орошения и городским водоснабжением, я решил подключить его к моей существующей спринклерной системе, чтобы получить воду для бассейна. По сути, я создавал еще одну «зону» для своей спринклерной системы, в комплекте с клапаном.
Это представляло проблему, заключающуюся в том, что, если мои разбрызгиватели работают, и я решаю заполнить бассейн, я ограблю всю зону газона, где протекает вода, и он не будет поливать газон должным образом. Поэтому мне пришлось придумать способ определить, работают ли спринклеры. Изначально я использовал часовой пояс «затемнения» - то есть, если бы я знал, что мои дождеватели работают с 3 до 6 утра, не заполняйте бассейн в течение этого времени. Но это казалось немного нетехническим. Изучая свою спринклерную систему Rachio, я узнал, что у них есть встроенный API, который позволяет мне программно запрашивать статус спринклерной системы. В моем случае у меня возник простой вопрос:вы бежите?
В моем случае я просто использовал простую команду curl, чтобы получить то, что мне нужно:
rachio_url ='curl -s -X GET -H "Content-Type:application / json" -H "Авторизация:носитель xxxx-xxxxx-xx-xxxx-xxxxx-xxx" https:/ /api.rach.io/1/public/device/00xx00x-00xxx000-xxx0x000-00x0x0x0/current_schedule '
Это вызывается моей функцией get_sprinkler_status следующим образом:
output =subprocess.check_output (pooldb.rachio_url, shell =True), если output =="{}":sprinklers_on ="Нет"
Мое основное приложение запускается каждые 60 секунд, поэтому, если мои спринклеры работают, я просто ничего не делаю еще 60 секунд и снова проверяю. В конце концов оросители перестанут работать, и бассейн начнет наполняться автоматически.
Чтобы фактически заполнить бассейн, я использовал обычный спринклерный клапан на 24 В переменного тока, который я купил в Home Depot. Я установил это с односторонним клапаном прямо в трубопровод моего бассейна, идущий к моему бассейну. Односторонний клапан предотвращает попадание воды в спринклерный клапан под давлением насоса во время работы насоса.
Водопровод с односторонним клапаном
Поскольку электрическая панель моего бассейна имеет напряжение 240 В и у меня нет нейтрали на панели, мне пришлось купить трансформатор с 240 на 24 В переменного тока. Достаточно просто. Однако я не хотел запускать трансформатор 24 × 7 без причины, поэтому я использовал реле, чтобы 1) включить трансформатор, а затем 2) взять выход 24 В переменного тока с трансформатора и подключить его к спринклерному клапану.
Настройка реле
Я использовал твердотельные реле Sainsmart (очень недорогие) в оптически изолированном режиме, где у меня есть отдельный вход питания для питания реле, в отличие от VCC 5 В или 3,3 В от Pi. Предполагается, что это поможет устранить помехи от реле.
Спринклерный клапан и интеллектуальный счетчик воды
Я также добавил интеллектуальный счетчик, который я могу читать в режиме реального времени, чтобы показать мне, что вода течет и сколько воды я использую с течением времени. Эта информация хранится в базе данных MySQL и хранится исторически:
Экран моей системы EmonCMS для счетчика воды в моем домеВласть, Власть, Власть
Теперь пришло следующее, что мне нужно было выяснить. Когда мой насос работал, если бы я пытался заполнить бассейн, я бы боролся с давлением насоса. Я определил, измеряя расход воды, что я потерял около 50% своего потока заполнения во время работы насоса, поэтому я решил, что было бы лучше вообще не заливать, пока насос работает. Поэтому мне нужен был способ контролировать мощность моего насоса и выяснять, работает он или нет.
В этом случае у меня был очень простой способ сделать это. Каждая электрическая цепь в моем доме контролируется системой электрического мониторинга. Эта система называется GEM и продается компанией Brultech.
Насос My Pool является основным потребителем энергии в моем доме
С помощью этой системы я могу контролировать все потребление электроэнергии в моем доме и в рамках мониторинга процесса, я храню эти данные в базе данных MySQL. Поэтому раз в минуту я просто запрашиваю свою базу данных MySQL и выясняю, сколько ватт в настоящее время использует моя панель пула.
, если pool_pump_running_watts> pooldb.max_wattage:pool_fill_control.led_control (PUMP_RUN_LED, "ON") pool_pump_running ="Yes" logger.debug ('PUMP_RUN_LED', если горит индикатор 'PUMP_RUN_LED), если должен быть включен. - if DEBUG:print («PUMP_RUN_LED должен быть ВЫКЛЮЧЕН. Это ЖЕЛТЫЙ светодиод»)
У меня есть различные кнопки, переключатели и светодиоды на физическом блоке, которые позволяют мне видеть, работают ли спринклеры, насос, заполняется ли бассейн или есть какая-то системная ошибка . Выше вы можете видеть, где я включаю и выключаю светодиодный индикатор работы насоса, когда это необходимо.
В дополнение к системным индикаторам у меня есть кнопка включения / выключения системы (вверху слева), которая позволяет мне использовать систему MightyHat для перезагрузки или выключения моего Pi без необходимости входа в Pi для сделайте это из интерфейса командной строки. У меня также есть переключатель мгновенного действия (второй слева), который позволяет мне вручную заполнять бассейн, когда я хочу, и, наконец, с левой стороны у меня есть переключатель DPDT, который физически прерывает питание моей системы к спринклерному клапану и запускает GPIO событие, чтобы сообщить системе, что мы вручную отключили заполнение пула. При срабатывании этого переключателя ничего не работает, и если что-то выйдет из строя программно, то в любом случае никакая энергия не сможет пройти от трансформатора к спринклерному клапану.
Контроллер бассейна - внешний
Управление насосом
Со временем я добавил еще одну деталь в свою систему управления пулом. Возможность управлять моим насосом с регулируемой скоростью Pentair. Войдите в Рассел Голдин (tageyoureit) и его проект программного обеспечения контроллера бассейна. Программное обеспечение Рассела позволило мне напрямую связаться с моим насосом для бассейна через интерфейс RS485. После подключения я могу напрямую запросить у насоса системную информацию, такую как частота вращения, галлоны в минуту и используемые ватты:
def get_pump_data (key):verbose_debug ("get_pump_data () Started") verbose_debug ("get_pump_data (), вызываемый с помощью '{}'" .format (key)) log ("INFO", " get_pump_data () вызывается с '{}' ".format (key)) if pump_control_active:global json try:req =urllib2.Request (pooldb.PUMP_DATA_URL) opener =urllib2.build_opener () f =opener.open (req) data =json.load (f) pump_data =data ["pump"] ["1"] [key] verbose_debug ("get_pump_data () return {}". format (pump_data)) log ("INFO", "get_pump_data () return { } ". format (pump_data)) verbose_debug (" get_pump_data () - Completed ") log (" INFO "," get_pump_data () - Completed ") if key ==" gpm ":pump_gpm =pump_data update_database (" pump_status "," pump_gpm ", pump_gpm) log (" INFO "," Current GPM:{} ". format (pump_gpm)) log (" DEBUG "," get_pump_gpm () Completed ") debug (" Current GPM:{} ". format (pump_gpm) )) verbose_debug ("get_pump_gpm () Completed") elif key =="rpm":pump_rpm =pump_data update_database ("pump_status", "pump_rpm", pump_rpm) log ("INFO", "Current RPM:{} ". format (pump_rpm)) log (" DEBUG "," get_pump_rpm () Completed ") debug (" Current RPM:{} ". format (pump_rpm)) verbose_debug (" get_pump_rpm () Completed ") else:pump_watts =pump_data update_database ("pump_status", "pump_watts", pump_watts) log ("INFO", "Current WATTS:{}". format (pump_watts)) log ("DEBUG", "get_pump_watts () Completed") debug ("Current WATTS :{} ". format (pump_watts)) verbose_debug (" get_pump_watts () Completed ") вернуть pump_data, кроме Exception as error:pump_data =0 debug (" EXCEPTION:get_pump_data () ") log (" WARN "," EXCEPTION:get_pump_data ( ) ") журнал (" ПРЕДУПРЕЖДЕНИЕ ", ошибка) отладка (тип (ошибка)) отладка (ошибка) verbose_debug (" get_pump_data () - Завершено с ИСКЛЮЧЕНИЕМ ") журнал (" ОТЛАДКА "," get_pump_data () - Завершено с ИСКЛЮЧЕНИЕМ ") return pump_data else:pump_data =0 return pump_data
Теперь я могу запрашивать насос и управлять своей помпой, добавляя еще одну возможность, которой у меня не было раньше. Изменив свой веб-интерфейс, я добавил возможность запускать или останавливать помпу, а также запускать одну из четырех различных программ помпы, которые я настроил на своей помпе:
Панель управления насосом
Конечно, мы можем смотреть на обороты, галлоны в минуту и ватты в реальном времени:
Манометры в веб-интерфейсе
Контроль давления в фильтре
Еще я хотел следить за давлением в фильтре, чтобы знать, когда нужно промыть фильтр обратно. Я купил датчик давления 100 фунтов на квадратный дюйм на ebay и привязал его к своему фильтру рядом с моим аналоговым манометром, уже установленным на фильтре.
Я купил недорогое устройство отправки на ebay (см. ссылку выше) и привязал его к своему фильтру следующим образом:
Блок отправления 100 фунтов на квадратный дюйм Блок передачи давления Блок передачи данных ..
Затем я привязал его к Moteino-R5 и считывал давление один раз в минуту, а затем выводил эту информацию в свою базу данных MySQL, а затем использовал эту информацию для выводить данные о датчике на моем веб-сайте.
// Получить наше давление фильтра void get_filter_pressure () {sensorVoltage =analogRead (PSI_SENSOR_PIN); // Считаем напряжение нашего датчика давления PSI =((sensorVoltage-146) / 204) * 25; // Некоторая калибровка для преобразования напряжения в PSI и его обнуления pool_sensors.PSI =PSI; }
Фильтр бассейна PSI Gauge
Дополнительное оборудование и программное обеспечение
Основная система полностью написана на Python, но я использовал другое программное и аппаратное обеспечение, чтобы моя система работала.
На моем Raspberry Pi я использую Low Power Labs MightyHat, который обеспечивает резервное питание ИБП для Pi, ЖК-экран состояния и интеллектуальное управление питанием для Pi. Я могу проработать Pi около двух часов на маленькой батарее, которую я подключил к системе, и если питание не вернется к нему вовремя, то MightyHat автоматически отключит Pi, чтобы предотвратить его сбой из-за внезапного сбоя. сбой питания.
MightyHat крупным планом на Pi3 с предупреждением о переполнении
MightyHat - это клон Arduino, поэтому я использовал IDE Arduino, чтобы запрограммировать его в соответствии с потребностями моего проекта.
Для восприятия я использую различные датчики и методы преобразования информации в удобный формат. Практически для всех данных датчиков я использую бесплатную платформу EmonCMS OpenEnergyMonitor.org. Эта платформа позволяет мне собирать все данные с датчиков из любого места в моем доме. Он хранит эту информацию в базе данных MySQL, откуда я могу получить ее для использования в моей системе управления пулом.
Некоторые из датчиков отслеживания моего бассейна Дополнительная информация отслеживания
Для определения фактического уровня бассейна я использую ленту для измерения сопротивления жидкости eTape (http://www.milonetech.com):
eTape и Moteino
Одна из моих плат контроллера ввода-вывода
Плата контроллера ввода-вывода, контроллер светодиода, интерфейс питания Плата контроллера ввода-вывода - задняя часть
Платы датчиков pH и ОВП с интерфейсом USB
Интерфейсные платы датчиков pH и ORP Atlas Scientific
Для получения точных значений pH и ORP я использую датчики pH и ORP Atlas Scientific, а также их интерфейсные платы. Я установил их в проточную ячейку, которая также отслеживает, работает ли насос. Я привязал проточную кювету к линиям с помощью стандартных быстроразъемных соединений John Guest 3/8 ″, одно на стороне нагнетания фильтра, а другое на стороне всасывания насоса, чтобы вода проходила через проточную кювету.
Проточная кювета (крайняя слева) Проточная кювета с датчиками John Guest 3/8 ″ Резьбовые быстрые соединения Линия обратного (всасывающего) выхода (давление) - установлена ДО инжектора кислоты
Чтение нашего pH:
def get_ph_reading ():log ("DEBUG", "get_ph_reading () Started") pool_pump_running =read_pool_sensor_status_values ("pool_sensor_status", "led_status", ") if_run_dump" pool_run_punning ",") if_run_pump " :if pooldb.temp_probe ==«Да»:pool_temp =float (read_pool_sensor_status_values («pool_sensor_status», «system_status», «pool_current_temp»)) ph_value =float (get_ph.get_current_valpue.ph_get_temp) (get_ph. ()) debug («Текущий pH:{}». формат (ph_value)) Infx_data.write_data («pH», ph_value) Infx_data.write_data («pool_temp», pool_temp) if pooldb.emoncms_server1 ==«Да»:res =requests.get ("http://" + pooldb.server1 + "/" + pooldb.emoncmspath1 + "/ input / post? &node =" + str (pooldb.ph_node) + "&csv =" + ph_value + "&apikey ="+ pooldb.apikey1) log (" DEBUG "," Отправлено текущее значение pH {} на сервер Emoncms 1 ".format (ph_value)) debug (" Отправлено текущее значение pH {} на сервер Emoncms 1 ".format ( ph_value)) если pooldb.emoncms_server2 =="Да":res =requests.get ("https://" + pooldb.server2 + "/" + pooldb.emoncmspath2 + "/ input / post? &Node =" + str (pooldb.ph_node) + "&csv ="+ ph_value +" &apikey ="+ pooldb.apikey2) log (" DEBUG "," Отправлено текущее значение pH {} на сервер Emoncms 2 ".format (ph_value)) debug (" Отправлено текущее значение pH {} на Emoncms Server 2 ".format (ph_value)) update_pool_sensor_status_values (" pool_sensor_status "," pool_chemicals "," pool_current_ph ", ph_value) log (" DEBUG "," get_ph Pool_reading () Completed ") else, log (" INFO " НЕ работает, невозможно получить точное значение pH! ") debug (" Насос бассейна НЕ работает, не может получить точное значение pH! ") log (" DEBUG "," get_ph_reading () Completed ")
Этот код вызывает модуль get_ph.py, который выглядит следующим образом:
#! / usr / bin / python ## Для использования с pool_control_master.py__author__ ='Richard J. Sears'VERSION ="V3.4 (2018-03-16)" # [электронная почта защищена ] # Это только для использования с платой pH Atlas Scientific. Import serialimport sysimport timefrom serial import SerialExceptionusbport ='/ dev / PH'try:ser =serial.Serial (usbport, 38400, timeout =0), кроме serial.SerialException как e:print "Error,", e sys.exit (0) def read_line ():lsl =len ('\ r') line_buffer =[] while True:next_char =ser.read (1) if next_char =='':break line_buffer.append (next_char) if (len (line_buffer)> =lsl and line_buffer [-lsl:] ==list ('\ r')):break return '' .join (line_buffer) def read_lines ():lines =[ ] try:while True:line =read_line () если не line:break ser.flush_input () lines.append (line) возвращать строки, кроме SerialException как e:print "Error,", e return Nonedef send_cmd (cmd):"" "Отправить команду на датчик Atlas. Перед отправкой добавьте возврат каретки в конце команды.:Param cmd::return:" "" buf =cmd + "\ r" # добавить возврат каретки try:ser.write (buf) return True, кроме SerialException как e:print "Error,", e return Nonedef get_current_ph_with_temp (current_temp):# send_cmd ("RESPONSE, 0") send_cmd ("C, 0") send_cmd ("T,% d"% current_temp) send_cmd ("R") time.sleep (1.3) lines =read_line () return linesdef get_current_ph_no_temp ():# send_cmd ("RESPONSE, 0") send_cmd ("C, 0") send_cmd ("R") time.sleep (1.3) lines =read_line () return linesdef main ():# send_cmd ("RESPONSE, 0") send_cmd ("C, 0") send_cmd ( «R») time.sleep (1.3) lines =read_lines () print («Калибровка температуры не выполнена:») для i в диапазоне (len (lines)):print lines [i] if __name__ =='__main__':main ()
ORP выполняется таким же образом.
В этой проточной кювете также установлен индикатор потока. Если вода течет через ячейку, кольцо поднимается и замыкает магнитный переключатель. Проводка переключателя подключается к выводу GPIO на пи. Вот мой код для чтения этого переключателя:
def pool_pump_running_chemical ():pool_pump_running_chemical =GPIO.input (pool_pump_running_pin) if pool_pump_running_chemical ==False:debug («Насос пула работает через камеру химического датчика:ИСТИНА - НАСОС ВЫПОЛНЯЕТСЯ (отладка) еще:«Насос бассейна работает через камеру химического датчика:ЛОЖЬ - НАСОС ВЫКЛЮЧЕН»)
Датчик уровня воды - заставляет его работать
Как я показал выше, датчик уровня воды использует батарею MoteinoUBS от LowPowerLab. Это идеальный микроконтроллер для этого приложения. Обычно я пробуждаю Moteino каждые шестьдесят секунд, снимаю показания сопротивления с eTape, включаю свой передатчик и отправляю эту информацию в мою систему EmonCMS для использования в сценариях моего пула. Затем снова выключаю все:
{digitalWrite (ETAPE_POWER, HIGH); // Включаем питание eTape pool.resistance =analogRead (ETAPE); // считываем сопротивление ленты digitalWrite (ETAPE_POWER, LOW); // Выключаем питание eTape take_battery_reading (); // Берем чтение батареи power_spi_enable (); rf12_sleep (RF12_WAKEUP); rf12_sendNow (0, &пул, размер пула); rf12_sendWait (2); rf12_sleep (RF12_SLEEP); power_spi_disable (); если (отладка) {flash_led (50); } // Вот и все - ждем до следующего раза :) sleep_until_next_reading (); }
Я также отслеживаю напряжение батареи, чтобы знать, когда пора сменить батареи. В скрипте есть несколько механизмов, чтобы убедиться, что батареи в порядке. Во-первых, я активно отслеживаю само напряжение батареи, а во-вторых, я отслеживаю, как часто датчики сообщают мне, и временную дельту этих отчетов. Ко многим пропущенным показаниям, и я знаю, что «что-то не так» с этим датчиком, и я получу уведомление Pushbullet, чтобы посмотреть, что не так. Кроме того, из-за потери датчика моя система наполнения бассейна переходит в режим ожидания и отказывается заполнять бассейн, так как не знает, когда остановиться.
Я использую 2 литиевые батареи AA, и пока они проработали более года без замены.
Чтобы обеспечить безопасность MoteinoUSB на уровне бассейна, мне понадобился какой-то водонепроницаемый корпус. Я выбрал всепогодную коробку Adafruit с прозрачной крышкой.
Кожух Adafruit для защиты от атмосферных воздействий
Затем я использовал кабельный ввод Adafruit PG-9, очень осторожно просверлил боковую часть коробки и установил кабельный ввод.
Кабельный ввод Adafruit PG-9
С помощью водонепроницаемого кабеля питания постоянного тока Adafruit я подключил eTape к MoteinoUSB и корпусу.
Водонепроницаемый кабель питания постоянного тока Adafruit. Готовый корпус датчика уровня воды.
Для дополнительной сухости я купил влагопоглотитель, чтобы поместить его в корпус, чтобы он впитал влагу, которая может попасть внутрь корпуса. Одна вещь, на которую следует обратить внимание, я усвоил на собственном горьком опыте (к счастью, датчики недорогие) - НЕ затягивать слишком сильно верхнюю часть или кабельные вводы. Это заняло немного проб и ошибок. В конце концов, после того, как я «думаю», что у меня все в порядке, я фактически наполняю свою раковину, помещаю корпус под воду и держу его сверху кастрюлей, наполненной водой. Я держу его в таком состоянии в течение нескольких часов, время от времени проверяя его правильность.
Теперь мне нужно было найти способ и место для установки датчика уровня воды. В моем бассейне у нас есть небольшой цементный бассейн, в котором раньше находился поплавок, который вручную добавлял воду в бассейн. Это давно заржавело, и его нельзя было отремонтировать, не вырвав цементную ограду. С этого и начался мой проект!
Цементный резервуар
Цементный резервуар соединен с бассейном небольшой линией 3/4 ″, которая позволяет мне видеть уровень воды, но дети, плещущиеся или возящиеся в бассейне, не повлияют на уровень вода в тазу. Это было идеальное место для крепления датчика eTape. Для фактического монтажа я взял кусок трубы из ПВХ, разрезал его пополам, а затем отшлифовал, чтобы он имел такую же круглую форму, как и цементный резервуар. Затем я прикрепил эту деталь эпоксидной смолой прямо к краю бассейна. Как только это было сделано, я использовал пару шурупов для гипсокартона и прикрутил клейкую ленту к трубе из ПВХ.
Датчик eTape, установленный на трубе из ПВХ Завершенный Установка датчика eTape
ОБНОВЛЕНИЕ:новый метод определения уровня воды!
Если вы читали выше, у меня были некоторые проблемы с моей установкой eTape, из-за которых мой eTape прекращал работу и давал ошибочные показания, что делало его непригодным для использования. Я переписывался с Крисом в Mileone, и мы не смогли подойти по той причине, что запись не удалась. В конце концов, мне не стоило еще 80 долларов, чтобы получить еще одну ленту и повторить то же самое снова, поэтому я изменил методы измерения уровня воды.
Поскольку на самом деле у меня разница между нижним и полным уровнями составляет всего 3 дюйма, я исследовал различные датчики уровня и выбрал этот:
Поплавковый выключатель датчика уровня воды в баке из нержавеющей стали Elecall
Тогда мне пришлось придумать способ установки нового датчика. Я решил, что воспользуюсь плексигласом 1/4 дюйма, чтобы он заработал. Я измерил необходимую мне ширину и установил поплавок с помощью дополнительного установочного винта, чтобы можно было произвести точную регулировку. Я также приклеил к нему небольшой уровень, чтобы, когда я его установил, он был ровным:
Чтобы смонтировать его, я просто использовал немного эпоксидной смолы и выровнял его, используя свой «встроенный уровень»:
Чтобы узнать уровень пула, мне нужно знать положение обоих поплавков. Поэтому я запрограммировал свой код так, чтобы он считывал положение обоих поплавков, а затем отправлял 0, 1 или 2 в зависимости от уровня воды.
Если верхний поплавок открыт, а нижний - открыт (оба плавают вниз), то у нас низкий уровень, и он отправляет «0». Если нижний поплавок закрыт (вверх), а верхний поплавок открыт (вниз), то мы на полпути и отправляем «1». Если оба поплавка закрыты (вверх), бассейн полон и вода нам не нужна. Вот как выглядит код:
UPPER_Float =digitalRead (17); LOWER_Float =digitalRead (3); если (UPPER_Float ==LOW) {UPPER_Float_Position ="Закрыто"; } else {UPPER_Float_Position ="Открыть"; } if (LOWER_Float ==LOW) {LOWER_Float_Position ="Закрыто"; } else {LOWER_Float_Position ="Открыть"; } if ((UPPER_Float ==LOW) &&(LOWER_Float ==LOW)) {pool_level.level =2; // Both closed =Pool is FULL } else if ((UPPER_Float ==HIGH) &&(LOWER_Float ==LOW)) { pool_level.level =1; // Lower closed, Upper open =Pool MIDWAY } else { pool_level.level =0; // Both floats open =Pool LOW add water }
So the value of 0, 1 or 2 is transmitted to EmonCMS and written to my database. Each minute we query that database to see if we need to add water:
get_pool_level_value =read_emoncms_database("data", pooldb.pool_level_table)
and if it is low, we add water:
if get_pool_level_value ==0:get_pool_level ="LOW" pool_fill_valve("OPEN")
And this is the new way we are reading our pool level and managing filling our pool.
Pool Temperature Sensor – Making it work
Following in the footsteps of my eTape sensor, I build the same configuration for my pool temperature sensor. This time however, I added a temp probe inside the enclosure so I could monitor the temperature in the enclosure. It would also let me know what the temperature was just above the surface of the water in the pool. The second temperature sensor was fed through the PG-9 cable gland and into the pool water. I then just tossed the enclosure into the pool and thought I was done. However, my kids had other ideas. They thought it was fun to grab the temperature sensor hanging down from the enclosure and spin it around like a top and throw it at each other. Needless to say the first one didn’t last long.
So I went down to my local pool store and purchased a chlorine floater and installed the enclosure and temp probe into it. We have not had a problem since doing so. Even if they throw it, it won’t bother it at all. Most people leave it alone since they think it is chlorine even though we have a saltwater pool.
Pool temp sensor floaterPool temp sensor floater
Keeping track of our Acid Level
Part of the pool automation system that is not handled by my project is the dispensing of muriatic acid to keep our pH under control. While the Pool Auto Pilot system handles that, we still need to be able to see if we need acid added to the tank. For this I used a $9.00 DFRobot Liquid Level Sensor:
XKC-Y25-T12V Liquid Level Sensor
This particular sensor is weatherproof and works by sensing when there is no longer liquid behind whatever you have it attached to and then sending a signal to the GPIO that you can read. Once you can read it, you can then do your alerting, etc.
I simply connected this to my Pi (it utilizes the 5v rail and one GPIO pin) and then added in a little bit of code to read the state of the sensor:
def acid_level():acid_level_ok =GPIO.input(acid_level_sensor_pin) if acid_level_ok ==True:
I then epoxied the sensor to our acid tank at the level where I wanted to be notified and hooked it all up:
This tank has a pretty thick wall and this sensor worked great. I tested it before affixing it just to make sure.
Web Interface
V3.5.0 Web Interface
Once I had all of this pretty much working like I wanted it, I decided that I needed to have a nice interface so we could track all of the data, manually add water to the pool without having to go to the pool room, stop an automatic fill that may be in progress and check the status of the batteries in our temperature sensor and our level sensor.
The main capabilities of the web interface as of right now are:
- Visually see all sensor data on nice gauges
- See system status including overall status, pump status, filling status, sprinkler status (we cannot fill while the sprinklers are running) and our Acid level
- Visually see battery status of pool level and temp sensors (including household temp sensors)
- See temperature and humidity inside the actual sensor boxes so I can see if I have a potential water leak in my “water proof” boxes.
- Have the ability to toggle various notifications such as debug, logging, email, pushbullet, and sms messages from the interface
- Control Pentair Intelliflo pool pump
I am very thankful to Russell Goldin ([email protected]) for his amazing work on the Pentair RS-485 control software needed for my system to be able to talk to and control my pump. You can check out his github HERE.
With Russ’s software I am able to directly control my Pentair pump without having to spend several thousand dollars on their proprietary hardware!
I spent a lot of time programming everything in python but I did not have an experience building a web interface so I asked around and eventually decided on Flask as the web framework that I would use to build the web interface.
Learning Flask was not as hard as I had thought it was going to be and it integrates very well with the python code that I had already written to control the pool. Flask is a mix of python-like code and html like templates and did everything that I needed it to do:
Upper Control PanelSystem GaugesLower Panel
The control part of the interface is very easy. If I want to start a manual fill, I simply click on the “Manual Fill” button and as long as there is not a system problem, we are not running the sprinklers and we are not already “automatically” filling the pool, the system starts a manual fill of the pool. The “Pool Filling” led will turn blue, than “Manual Fill” button will toggle on and the “Fill Timer” will start a countup. Click the “Manual Fill” button again and the system stops filling and reverts back to normal.
If we are filling the pool automatically and I want to stop that process, I simply click the “Pool Filling” button (led reverts to button to show that you can push it to stop the automatic fill) and the system stops filling and sends me notifications based on the configuration of the system (debug, logging, email, pushbullet, sms).
Flask has the ability to process things prior to showing you the html output:
{% if system_error_led =="True" %} {% elif system_run_led =="True" %} {% else %} {% endif %}
In this example, if there is a system error I show a red led, otherwise if the system is running I show a green led and if I am not running and there is no error, then I show a grey led. This statement is processed before the html is rendered and is a very powerful way to interact with a python driven system.
Historical Graphing
As I continue to extend the system and learn more about what I can do, I wanted to start to watch historical trends in my pool system along with a lot of other home automation stuff I have been playing around with lately. After looking around I choose Grafana and InfluxDB.
Basically I already had my data being recorded utilizing EmonCMS so I just needed to have a quick way to get it into InfluxDB so Grafana could do it’s magic. Basically within the mail pool program whenever I get a pH, ORP or temp reading, I write it to the influxdb:
def get_ph_reading():log("DEBUG", "get_ph_reading() Started") pool_pump_running =read_pool_sensor_status_values("pool_sensor_status", "led_status", "pump_run_led" ) if pool_pump_running =="True":if pooldb.temp_probe =="Yes":pool_temp =float(read_pool_sensor_status_values("pool_sensor_status", "system_status", "pool_current_temp" )) ph_value =float(get_ph.get_current_ph_with_temp(pool_temp)) else:ph_value =float(get_ph.get_current_ph_no_temp()) debug("Current pH is:{}".format(ph_value)) influx_data.write_data("pH", ph_value) influx_data.write_data("pool_temp", pool_temp) if pooldb.emoncms_server1 =="Yes":res =requests.get("http://" + pooldb.server1 + "/" + pooldb.emoncmspath1 + "/input/post?&node=" + str( pooldb.ph_node) + "&csv=" + ph_value + "&apikey=" + pooldb.apikey1) log("DEBUG", "Sent current pH Value of {} to Emoncms Server 1".format(ph_value)) debug("Sent current pH Value of {} to Emoncms Server 1".format(ph_value)) if pooldb.emoncms_server2 =="Yes":res =requests.get("https://" + pooldb.server2 + "/" + pooldb.emoncmspath2 + "/input/post?&node=" + str( pooldb.ph_node) + "&csv=" + ph_value + "&apikey=" + pooldb.apikey2) log("DEBUG", "Sent current pH Value of {} to Emoncms Server 2".format( ph_value)) debug("Sent current pH Value of {} to Emoncms Server 2".format( ph_value)) update_pool_sensor_status_values("pool_sensor_status", "pool_chemicals", "pool_current_ph", ph_value) log("DEBUG", "get_ph_reading() Completed") else:log("INFO", "Pool Pump is NOT running, cannot get accurate pH reading!") debug("Pool pump is NOT running, cannot get accurate pH reading!") log("DEBUG", "get_ph_reading() Completed")
and from influx_data.py:
import syssys.path.append('../')from influxdb import InfluxDBClientimport pooldbdef write_data(measurement, value):client =InfluxDBClient(pooldb.influx_host, pooldb.influx_port, pooldb.influx_user, pooldb.influx_password, pooldb.influx_dbname) json_body =[ { "measurement":measurement, "fields":{ "value":value } } ] client.write_points(json_body)
From there it is a simple matter of setting up Grafana to look at the InfluxDB and make the graphs:
Notifications
My system relies heavily on notifications. Currently the system can provide notifications via logging to a log file, debug messages to stdout allowing for the running of the main program from the command line with valuable, immediate feedback, pushbullet, email and SMS via Twillio. Because of all they types of notifications as well as areas where there can be notifications, I created a system which allows me to fine tune my notifications very easily via my web interface.
By setting up the code in this manner, I can very easily and quickly adjust my notification settings as well as different categories that I want to have those notifications applied to at that time. In future versions of the code, I am going to create an entire “Notifications” panel that allows me the ability to set specific notification types by category. For example I might want an SMS message about filling events, but email notifications about system errors and pushbullet notifications about my pump. In this manner I am able to tweak all of my notification settings to be exactly how I want then to notify me…both the how and the when!
Current Notification Settings Panel
root scruffy:www # ./pool_control_master.pyStarted is_database_online()MightyHat Serial setup completedSystem Reset Status =No Reset RequestedStarted get_pool_temp()get_pool_temp returned 67.30Fpool_temp in C is 19.61Started is_pool_pump_running()pool_pump_running_watts returned 563 watts in use by pump.PUMP_RUN_LED should be ON. This is the YELLOW LEDCurrent unix datetime stamp is:1521835161Pool LEVEL sensor last updated at:1521835044Pool LEVEL sensor battery voltage is:3.2Pool LEVEL sensor battery percentage is 100Pool TEMP sensor last updated at:1521835131Pool TEMP sensor battery voltage is:3.2Pool TEMP sensor battery percentage is 100Pool FILTER PSI is:21Time dfference between last pool LEVEL sensor reading is:117 seconds.Time dfference between last pool TEMP sensor reading is:30 seconds.Everything appears to be OK with the pool sensors!pool_sensors:Pool Resistance is:724pool_sensors:Pool Level Percentage is:85pooldb:Static critical pool level resistance set at (740).pooldb:Static normal pool level resistance set at (710).Our Pool Level is MIDWAY.Total Gallons:22462Acid Level OKTotal Current Power Utilization:2039 wattsTotal Current Power Import:415 wattsTotal Current Solar Production:1624 wattsCurrent GPM:15Current RPM:2225Starting get_ph_reading().Current pH is:7.043Sent Emoncms Server 1 current PH Value:7.043Sent Emoncms Server 2 current PH Value:7.043Completed get_ph_reading()Starting get_orp_reading().Sent Emoncms Server 1 current ORP Value:669.8Sent Emoncms Server 2 current ORP Value:669.8Completed get_orp_reading()
Running from the cli
Alexa Skill and Interface
One of the last things I wanted to tackle was to integrate my pool control system with Alexa. We have Echo Dots and Echo Shows and I wanted to use the visual Echo Show when I could. So I spent a bunch of time learning how to do Alexa skills and then I used the Python microframework Flask-Ask to program the interconnection between my pool control system and the Alexa Skill.
It was a very interesting learning curve, but now I can query Alexa and get all of our pool stats and we can fill (or stop filling) our pool via voice commands:
Alexa Show Interface with pool, electrical and solar stats
Conclusion
I am running V3.5.0 of my code now which seriously changes the way I am checking sensors, and handling error checking. I have also started breaking out my code into separate python functions instead of a monolithic block of 4,000+ lines of code. I will put it up and include all of the Flask programming as well.
This project has taught me a lot about programming, the Pi and Arduinos.
Pool Control System – InternalPool Control System – External
To view all of the code, please visit my Github site HERE! Thank you for reading about my project.
Source: Pool Fill Control
Производственный процесс