[Перевод] Raspberry Pi, Python и полив комнатных растений
У меня не складываются отношения с комнатными растениями. Дело в том, что я забываю их поливать. Зная это, я начал размышлять о том, что кто-то, наверняка, уже нашёл способ автоматизации полива. Как оказалось, способов таких существует очень много. А именно, речь идёт о решениях, основанных на Arduino или на Raspberry Pi. В этом материале я хочу рассказать о том, как создал систему, основанную на Raspberry Pi и Python, предназначенную для автоматизации полива растений.
Компоненты и полезные ресурсы
Мне сразу хотелось бы отметить, что я вовсе не являюсь экспертом в электронике. Если меня попросят нарисовать электрическую схему, или подробно рассказать о том, как, работает какой-нибудь электронный компонент, я ничего толкового нарисовать или рассказать не смогу. На самом деле, я сделал этот проект, обладая лишь базовыми знаниями об электричестве и просто экспериментируя с компонентами. Прошу вас очень осторожно относиться к работе с электричеством. А, если вы чувствуете недостаток знаний в этой области, предлагаю хотя бы немного в этом разобраться.
Вот список компонентов, которые я использовал в своём проекте.
Я участвую в партнёрской программе Amazon, поэтому выше приведены соответствующие ссылки. Если вы, перейдя по ним, что-нибудь купите, я немного заработаю.
После того, как я раздобыл все необходимые мне компоненты, пришло время заняться некоторыми изысканиями. Ниже приведён список ресурсов, которые помогли мне правильно соединить электронные компоненты и понять основные моменты, касающиеся их функционирования:
Вот схема GPIO-портов Raspberry Pi.
Схема GPIO-портов Raspberry Pi
Подключение реле к Raspberry Pi
Я начал с подключения реле к Raspberry Pi. Вот как это выглядит.
Подключение реле к Raspberry Pi
Красный провод (Female-Female) идёт от пина платы реле JD_VCC к 5V-пину (контакт №2) Raspberry Pi. Оранжевый провод (Female-Female) ведёт от пина платы реле VCC к 3.3V-пину (контакт №1) Raspberry Pi.
Пины JD_VCC и VCC платы реле
С помощью этих проводов мы подаём питание на плату реле. Для того чтобы получить возможность управлять отдельными реле, нужно соединить плату реле и Raspberry Pi ещё двумя проводами, которые подключаются к пинам GND и IN1 платы реле.
Пины GND и IN1 платы реле
Чёрный провод (Female-Female) — это кабель заземления, который соединяет пин GND платы реле и контакт заземления на Raspberry Pi (я подключил его к контакту №34). Белый провод (Female-Female) ведёт от пина IN1 платы реле к контакту №12 Raspberry Pi. Именно этот белый провод позволяет нам программным способом управлять реле, включая и отключая отдельные реле, расположенные на плате.
Чёрный и белый провода, подключённые к Raspberry Pi
Если вы решите воспроизвести мой проект — вы можете организовать связь реле и Raspberry Pi, пользуясь любыми подходящими пинами. Но учитывайте, что если схема соединения компонентов вашего проекта будет отличаться от схемы соединения компонентов моего проекта — вам придётся внести соответствующие изменения в мой код.
Подключение блока питания к реле
После того, как я присоединил плату реле к Raspberry Pi, я подключил блок питания к одному из реле.
Не подключайте блок питания к розетке до тех пор, пока не завершите все операции по сбору компонентов системы. Помните о риске поражения электрическим током.
Подключение блока питания к одному из реле
Используемый мной блок питания на 12V поставляется с адаптером, к которому удобно подключать соединительные провода. Я подключил красный провод (Male-Male) к разъёму »+» адаптера, а коричневый кабель (Male-Male) — к разъёму »-» адаптера. Затем я подключил кабель с разъёмом «крокодил» (Female-Male) к коричневому проводу.
Адаптер, который поставляется с блоком питания
На плате реле имеется четыре отдельных реле. У каждого из них есть три контакта, к которым можно подключать кабели. В центре каждого реле находится разъём, к которому подключают положительный вывод внешнего источника питания. Слева находится разъём, к которому подключают положительный вход устройства, на которое нужно подавать питание.
Подключение отдельного реле
Я подключил красный кабель от блока питания (положительный вывод) к центральному контакту реле. Затем я подключил оранжевый кабель (Male-Male) к левому разъёму реле и подключил к этому кабелю кабель с «крокодилом» (Female-Male).
Красный и оранжевый кабели
Блок питания и адаптер
Реле и Raspberry Pi
Подключение водяного насоса к реле
Теперь осталось лишь подключить разъёмы «крокодилы» к водяному насосу. Порядок их подключения определяет направление тока воды.
Так, мне нужно было, чтобы вода поступала бы в левый канал насоса и выходила бы из правого канала. Поэтому я подключил разъём «крокодил» чёрного провода к выводу насоса, около которого имеется красная точка, а другой «крокодил» — к другому выводу насоса. Если бы я подключил «крокодилы» в другом порядке — вода пошла бы в обратном направлении — из правого канала в левый.
Подключение водяного насоса к реле
Система полива в сборе: вода поступает в насос через левый канал, выходит из правого и идёт к растению
Код
Вот мы и добрались до того, в чём я по-настоящему хорош. Мы дошли до кода. Для того чтобы наладить программную работу с GPIO-портами Raspberry Pi, я использовал библиотеку gpiozero. Пользоваться ей легко, она скрывает от программиста массу низкоуровневых механизмов, с которыми обычно нужно разобраться тому, кто хочет работать с GPIO-пинами. Библиотека хорошо документирована.
Прежде чем заниматься написанием кода, к Raspberry Pi нужно подключить монитор, мышь и клавиатуру. Или нужно подключиться к Raspberry Pi по SSH.
После того, как вы войдёте в Raspberry Pi, перейдите к папке Desktop
и создайте там папку run
. В этой папке создайте папку classes
. А в папке classes
создайте файл Hardware.py
. В нём должен быть следующий код:
from gpiozero import OutputDevice
class Relay(OutputDevice):
def __init__(self, pin, active_high):
super(Relay, self).__init__(pin, active_high)
В этом файле я всего лишь объявил новый класс Relay
, который является наследником класса OutputDevice.
Далее, в папке classes
я создал новый файл TimeKeeper.py
:
import datetime
class TimeKeeper:
def __init__(self, current_time):
self.current_time = current_time
self.time_last_watered = None
def set_current_time(self, updated_time):
self.current_time = updated_time
def set_time_last_watered(self, updated_time):
self.time_last_watered = updated_time
@staticmethod
def get_current_time():
now = datetime.datetime.now()
return now.strftime("%I:%M:%S %p")
Цель этого класса заключается в отслеживании текущего времени и того момента, когда в прошлый раз выполнялся полив.
Итак, файлы Hardware.py
и TimeKeeper.py
находятся в папке classes
. Теперь я, за пределами этой папки, создаю файл water_plant.py
:
from classes import Hardware
from classes import TimeKeeper as TK
import schedule
import smtplib
import time
import ssl
# WATERING_TIME must be in "00:00:00 PM" format
WATERING_TIME = '11:59:50 AM'
SECONDS_TO_WATER = 10
RELAY = Hardware.Relay(12, False)
EMAIL_MESSAGES = {
'last_watered': {
'subject': 'Raspberry Pi: Plant Watering Time',
'message': 'Your plant was last watered at'
},
'check_water_level': {
'subject': 'Raspberry Pi: Check Water Level',
'message': 'Check your water level!',
}
}
def send_email(time_last_watered, subject, message):
port = 465
smtp_server = "smtp.gmail.com"
FROM = TO = "YOUR_EMAIL@gmail.com"
password = "YOUR_PASSWORD"
complete_message = ''
if time_last_watered == False:
complete_message = "Subject: {}\n\n{}".format(subject, message)
else:
complete_message = "Subject: {}\n\n{} {}".format(subject, message, time_last_watered)
context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
server.login(FROM, password)
server.sendmail(FROM, TO, complete_message)
def send_last_watered_email(time_last_watered):
message = EMAIL_MESSAGES['last_watered']['message']
subject = EMAIL_MESSAGES['last_watered']['subject']
send_email(time_last_watered, subject, message)
def send_check_water_level_email():
message = EMAIL_MESSAGES['check_water_level']['message']
subject = EMAIL_MESSAGES['check_water_level']['subject']
send_email(False, subject, message)
def water_plant(relay, seconds):
relay.on()
print("Plant is being watered!")
time.sleep(seconds)
print("Watering is finished!")
relay.off()
def main():
time_keeper = TK.TimeKeeper(TK.TimeKeeper.get_current_time())
if(time_keeper.current_time == WATERING_TIME):
water_plant(RELAY, SECONDS_TO_WATER)
time_keeper.set_time_last_watered(TK.TimeKeeper.get_current_time())
print("\nPlant was last watered at {}".format(time_keeper.time_last_watered))
# send_last_watered_email(time_keeper.time_last_watered)
# schedule.every().friday.at("12:00").do(send_check_water_level_email)
while True:
# schedule.run_pending()
time.sleep(1)
main()
Тут можно поменять значения переменных WATERING_TIME
и SECONDS_TO_WATER
на те, которые кажутся вам подходящими. Первая переменная определяет то, в какое время нужно поливать растения. Вторая задаёт длительность полива.
Кроме того, я создал тут механизм рассылки уведомлений и напоминаний по электронной почте. Благодаря этому механизму владелец системы полива получает электронное письмо каждый раз, когда система включается и поливает растения. Кроме того, каждую пятницу он получает письмо с напоминанием о том, что ему нужно проверить запасы поливочной воды. В коде вызов соответствующих методов закомментирован, в результате программа может нормально работать и без настроек, касающихся электронной почты. Если вы хотите эти напоминания включить — надо сделать следующее:
- Надо ввести в строки
FROM = TO = «YOUR_EMAIL@gmail.com»
иpassword = «YOUR_PASSWORD»
ваш адрес электронной почты Gmail и пароль. - Нужно раскомментировать следующие строки:
- # send_last_watered_email (time_keeper.time_last_watered)
- # schedule.every ().friday.at (»12:00»).do (send_check_water_level_email)
- # schedule.run_pending ()
- Нужно перейти сюда, войти в учётную запись Gmail и включить переключатель, имеющийся на данной странице. В противном случае при попытке отправить письмо с использованием Gmail вы получите сообщение об ошибке.
Кроме того, тут важно отметить, что моя система напоминаний работает только с учётными записями Gmail.
Теперь, когда всё готово к работе, у вас должна получиться следующая структура файлов и папок:
run
├── classes
│ ├── Hardware.py
│ └── TimeKeeper.py
└── water_plant.py
Папку run
можно, на самом деле, разместить где угодно. Я решил оставить её в папке Desktop
.
Меня не прельщала перспектива подключаться к Raspberry Pi каждый раз, когда надо было запустить water_plant.py
. Мне хотелось, чтобы этот скрипт запускался бы автоматически при включении Raspberry Pi. Это, например, позволило бы легко отключить систему, перенести её в другое место, включить, и уже ни о чём не беспокоиться. Для того чтобы реализовать этот привлекательный сценарий, нам понадобится команда crontab
.
Откроем на Raspberry Pi окно терминала и введём следующую команду:
sudo crontab -e
В ответ на неё система должна вывести нечто, напоминающее то, что изображено на следующем рисунке.
Настройка задач cron
В этот файл нужно добавить следующую строчку:
@reboot python3 /home/pi/Desktop/run/water_plant.py
Затем этот файл надо сохранить, воспользовавшись комбинацией клавиш Ctrl+X
, введя Y
и нажав Enter
.
Вышеописанной строкой мы даём Raspberry Pi следующие инструкции: «Каждый раз, когда ты перезагружаешься, запускай файл water_plant.py
, находящийся в папке run
, котораях находится в папке Desktop
». Если у вас папка run
находится по другому пути — отредактируйте соответствующим образом эту команду.
Итоги
Посмотреть код проекта можно здесь. Если хотите — можете сразу клонировать себе репозиторий такой командой:
git clone https://github.com/AlanConstantino/rpi-plant-project.git
Вот и всё! Теперь вы знаете о том, как создать систему автоматизированного полива комнатных растений, основанную на Raspberry Pi. Она умеет поливать растения каждые 24 часа и может отправлять своему владельцу уведомления и напоминания по электронной почте.
Уважаемые читатели! Как бы вы подошли к разработке домашней автоматизированной системы полива растений?