Умная теплица в Telegram

- КиТ :: Будь в СЕТИ!

Добрый день

На нашем участке имеется теплица. Её главная проблема — перегрев в жаркое время, т.к. рассчитана в первую очередь на сибирскую весну. Единственный выход — постоянно открывать/закрывать двери и окна, чтобы поддерживать температуру. Но это не всегда возможно. А если это не сделать, то температура поднимается до +50 градусов, что явно не хорошо. А вечером всё можно заморозить. Так и началась её автоматизация. В первую очередь мы купили Raspberry Pi 2. Разобравшись с ним, подключили датчик DS18B20 по этой . Затем были куплены два б/у автомобильных стеклоподъёмника. Как и все DC двигатели, они движутся в зависимости от полярности. Поэтому к каждому двигателю подключаем два реле: одно для открытия, другое для закрытия. Эти реле уже через транзисторы подключаем к самим портам GPIO. И питаем это всё дело аккумулятором 12V. Так же, чтобы не сжечь двигатели, в крайних положениях окна были установлены концевые выключатели, и в случае, если окно открылось/закрылось полностью рвут сеть.

А для связи мы используем WiFi адаптер TP-LINK с усовершенствованной антенной «Двойной квадрат» для уверенного приёма соседского WIFI домашнего WIFI роутера, который находится на расстояние 40 метров. Теперь пишем программу для управления этими приводами. Был выбран язык Python, т. к. у него нормальная поддержка Raspberry Pi и конкретно GPIO портов. Для того, чтобы открыть окно, нам нужно подать +3.3V на транзистор, который активирует реле, и то начнёт открывать окно. Чтобы его закрыть, делаем то же самое, только в это случаем наше реле подключено наоборот к приводу. Но на Raspberry мы просто подаём ток то на один порт, то на другой. Мы решили, что если температура больше 26 открываем окно в течение 1 секунды. Затем ждём 3 минуты. Если опять жарко, то открываем второе окно в течение секунды. Ждём опять 3 минуты, и делаем заново. То же самое с закрытием, только тут температура должна быть ниже 24 градусов. А вот и код: А теперь начинается шоу для тех, кому физика не интересна.

Установив Apache на дистрибутив Raspbian, мы в течение месяца не могли достучаться до странички из интернета. Что только не делали. Настраивали порты, открывали их, ничего не помогала. Причём в локальной сети всё работали. Потом мы узнали печальную правду: мы находимся за NAT. И услуг по выделенному IP наш оператор не предоставляет (Привет сотрудникам Регион Телекома). Перебирали много обходных методов, но ничего не выходило. Пытался сделать веб интерфейс на хостинге, но для синхронизации базы данных тоже нужен IP. Брокер IPv6 к тому времени уже закрылся. А делать VPN дорого, ведь хочется всё бесплатно. И тут решили использовать Telegram бота. Как оказалось он имеет два режима: постоянный опрос сервера и отправка сообщений прямо к нам. Первый вариант подходил, т.к. не требует от нам IP адреса. Покопавшись в интернете нашёл библиотеку: pytelegrambotapi. И принялся за написание кода. Правда выходили и проблемы. Еле найденная MySQL библиотека отказывалась писать в базу данных, но при это читала из неё всё нормально. Пришлось делать костыль: передавать данные в файл, хранящийся в ОЗУ, затем запускать bash скрипт, который считает данные и занесёт в БД.

Делаем файл config.ini, туда кидаем: Не забываем данные заменить на свои.

Создаём файл python_mysql_dbconfig.py, со следующим содержимым: Так же нам нужно создать файл python_mysql_connect2.py, с вот таким содержимым: Теперь мы всё подготовили для работы с БД.

Отвлечёмся немного от базы данных и перейдём непосредственно к общению с ботом. Ну как обычно, пишем @BotFather, и берём у него токен. Создаём файл config.py, и пишем в него две строчки: Я решил реализовать в боте три функции:

Получение температуры Получение снимков Управление окнами

С первым всё просто, по запросу читаем файл с температурой, и отправляем это пользователю.

Со снимками посложнее. Я использую утилиту Motion. В её параметрах проси класть в папку в оперативной памяти снимки, ну допустим каждые 30 секунд. И делаем файлы с одинаковыми имена, и они просто заменяют друг друга. А потом по запросу отправляем файл пользователю.

Ну и третий, самый сложный модуль: управление окнами. У меня главная задача: чтобы работала автоматика, но если нужно, то мы её можем отключить. Делал я это так. Создал в оперативной памяти очередной файл. Когда мы отправляем запрос на открытие/закрытие, приоткрытие, призакрытие окна или на включение/выключение автоматики бот пишет в этот файл номер команды. Каждые пять секунд программа управления окнами считывает этот файл, и если распознаёт команду, выполняет её. После выполнение в этот же файл пишет, что всё прошло успешно. Бот опять читает файл, и уведомляет нас, что команда выполнена.

Ну а теперь исходный код. Сначала та же самая программа для открывания окон, только уже переделанная под бота(temp.py): Так же давайте сразу сделаем ещё несколько вспомогательных скриптов. Создаём файл newuser.sh и пишем в него: И создадим два скрипта для запуска бота и программы окон: И ещё один: «Зачем мы это делаем?» спросите вы. А тут дело в том, что иногда из-за нестабильного интернет соединения, или ошибки на сервера Telegram программа может вылететь. А скрипт её гоняет в вечном цикле: вылетела — запустил через 5 секунд снова. А для окон я сделал это на всякий пожарный: вдруг тоже из-за сбоя программа вылетит, а нас в теплице нет, вернёмся и будет у нас томатный суп или помидорное мороженное.

Ну и теперь самое главное, скрипт самого бота:

bot.py

# -*- coding: utf-8 -*- import config import telebot import subprocess import time from telebot import types import datetime import os from daba import getkey from daba import sendup from daba import getid #from daba import newuser #from temp import tep import os #Создаём файл f = open('/mnt/raw/user', 'tw', encoding='utf-8') f.close() global par par=0 #Текст для неавторизированного пользователя global a a="Вы не авторизированны. Пройдите авторизацию командой /auth [пароль]" #Функция получение температуры def get_temp(): if os.path.isdir("/sys/bus/w1/devices/id датчика"): tfile2=open("/sys/bus/w1/devices/id датчика/w1_slave") ttext2=tfile2.read() tfile2.close() temp2=ttext2.split("\n")[1].split(" ")[9] t2=float(temp2[2:])/1000 return t2 else: print ('File not found') #Пароль keyword=str(getkey())[2:-3] #Конфигурация токена bot = telebot.TeleBot(config.token) print (sendup()) #Создание кастомной клавиатуры #########################Клавиатура авторизации########################################## markup2 = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду markdown = types.ReplyKeyboardHide() #Деактивация itembtn5 = types.KeyboardButton(' Авторизация') #Название кнопки 5 markup2.add(itembtn5) #Занесение кнопок в матрицу #########################Клавиатура авторизации########################################## #########################Клавиатура главного меню########################################## markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn1 = types.KeyboardButton(' Прислать снимок') #Название кнопки 1 itembtn4 = types.KeyboardButton(' Управление окнами') itembtn2 = types.KeyboardButton(' Прислать температуру') #Название кнопки 2 markup.add(itembtn1, itembtn4, itembtn2) #Занесение кнопок в матрицу #########################Клавиатура главного меню########################################## #########################Ещё кнопки########################################## markup3 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn10 = types.KeyboardButton(' Выключить автоматику ') #Название кнопки 10 itembtn11 = types.KeyboardButton(' Ручное управление') itembtn12 = types.KeyboardButton(' Назад') markup3.add(itembtn10, itembtn11, itembtn12) #Занесение кнопок в матрицу markup4 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn13 = types.KeyboardButton(' Включить автоматику ') #Название кнопки 13 markup4.add(itembtn13, itembtn11, itembtn12) #Занесение кнопок в матрицу markup5 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn14 = types.KeyboardButton(' Первое окно') #Название кнопки 14 itembtn15 = types.KeyboardButton(' Второе окно') #Название кнопки 15 itembtn16 = types.KeyboardButton(' Назад') #Название кнопки 16 markup5.add(itembtn14, itembtn15, itembtn16) #Занесение кнопок в матрицу markup6 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn17 = types.KeyboardButton(' Открыть окно ') #Название кнопки 17 itembtn18 = types.KeyboardButton(' Закрыть окно ') #Название кнопки 18 itembtn19 = types.KeyboardButton(' Приоткрыть окно ') #Название кнопки 19 itembtn20 = types.KeyboardButton(' Призакрыть окно ') #Название кнопки20 itembtn21 = types.KeyboardButton(' Назад') #Название кнопки 21 markup6.add(itembtn17, itembtn18, itembtn19, itembtn20, itembtn21) #Занесение кнопок в матрицу markup7 = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) #Активация, название, колва кнопок в одной ряду itembtn22 = types.KeyboardButton(' Открыть окно ') #Название кнопки 22 itembtn23 = types.KeyboardButton(' Закрыть окно ') #Название кнопки 23 itembtn24 = types.KeyboardButton(' Приоткрыть окно ') #Название кнопки24 itembtn25 = types.KeyboardButton(' Призакрыть окно ') #Название кнопки25 markup7.add(itembtn22, itembtn23, itembtn24, itembtn25, itembtn21) #Занесение кнопок в матрицу #########################Ещё кнопки########################################## bot.send_message(45215125, "Перезагрузка")#Вставьте сюда ваш chat-id #Узнаем состояние автоматики окон def pos(): f = open('/mnt/raw/pos') com = f.read() f.close() return com #Авторизация def avtor(idi): global par#Если пользователь храниться в переменной возвращаем ноль if par==idi: return 0 else:#Запрашиваем наличие пользователя в БД, если он там есть, возвращаем 0 if getid(str(idi))==20: par=idi#Заносим пользователя в переменную return 0 else:#Пишем что мы не знаем пользователя bot.send_message(idi, "Вы не авторизированны. Пройдите авторизацию командой /auth [пароль]", reply_markup=markup2) return 1 @bot.message_handler(regexp=" Авторизация") def auth(message): bot.send_message(message.chat.id, "Введите /auth [пароль]") #Тоже аворизация @bot.message_handler(command

ПодпискаБудь в СЕТИ! Новости социальных сетей - всегда актуальное
 
Группы: ВК | OK | Tg