Добрый день. На нашем участке имеется теплица. Её главная проблема — перегрев в жаркое время, т.к. рассчитана в первую очередь на сибирскую весну. Единственный выход — постоянно открывать/закрывать двери и окна, чтобы поддерживать температуру. Но это не всегда возможно. А если это не сделать, то температура поднимается до +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):
Но а теперь поговорим про самого бота. Как я уже говорил, я использую библиотеку PyTelegramBotApi. Если обратиться к документации на GitHub, то можно понять что для обработки команд бот использует хендлеры. Хендлер — это событие в нашей программе, определяющие действие. В нашей случае это определенная фраза в сообщение. А действие это всё что мы можем сделать в языке python. В данном случае мы будет присылать пользователю какую-нибудь информацию пользователю или записывать команды для окон в файл. В основном наша программа состоит из этих самых хендлров и команды опроса сервера.
Но так же я сам написал и добавил ещё одно интересную вещь: блок авторизации. Ну как понятно из названия, он сделан для защиты нашей теплицы от несанкционированного доступа. Он работает просто. При первом подключение к боту он запрашивает у нас пароль. Если мы его вводим правильно, бот добавляет нас в базу данных, и при следующих подключениях нам уже авторизироваться не нужно. Бот узнаёт нас при помощи chat-id. Chat-id последнего пользователя храним в переменно, чтобы всё время не дёргать базу.
Теперь создаём файл daba.py и пишем туда вот это:
Так же давайте сразу сделаем ещё несколько вспомогательных скриптов. Создаём файл newuser.sh и пишем в него:
И создадим два скрипта для запуска бота и программы окон:
И ещё один:
«Зачем мы это делаем?» спросите вы. А тут дело в том, что иногда из-за нестабильного интернет соединения, или ошибки на сервера Telegram программа может вылететь. А скрипт её гоняет в вечном цикле: вылетела — запустил через 5 секунд снова. А для окон я сделал это на всякий пожарный: вдруг тоже из-за сбоя программа вылетит, а нас в теплице нет, вернёмся и будет у нас томатный суп или помидорное мороженное.
Ну и теперь самое главное, скрипт самого бота:
Не забываем указать здесь id датчика, chat-id и путь к разделу в оперативной памяти. Теперь у нас почти всё готово. Качаем этот дамп, и заливаем базу данных на свой сервер, и не забываем смонтировать раздел в оперативной памяти, думаю 10 МБ хватит по горло. Запускаем два наших скрипта-стартера и радуемся. Пароль по умолчанию: telbot. Меняем его в таблице tkey базы данных.
Так же сделал СМС информирование на случай перегрева. Создаём файл sms.py:
Регистрируемся на sms.ru и берём там API-key в разделе для программистов. Так же не забываем указать в скрипте ваш номер телефона.
В программе для управления окон объявляем переменную:
Затем вставляем в вечный цикл этот код:
В данный момент температура порога 32, смс будут отправляться в случае высокой температуры раз в час, пока она не спадёт.
P.S. В планах на будущее установить управляемый обогреватель и сделать автоматический полив.
Спасибо всем тем, кто дочитал до конца.
В первую очередь мы купили Raspberry Pi 2. Разобравшись с ним, подключили датчик DS18B20 по этой статье. Затем были куплены два б/у автомобильных стеклоподъёмника. Как и все DC двигатели, они движутся в зависимости от полярности. Поэтому к каждому двигателю подключаем два реле: одно для открытия, другое для закрытия. Эти реле уже через транзисторы подключаем к самим портам GPIO. И питаем это всё дело аккумулятором 12V. Так же, чтобы не сжечь двигатели, в крайних положениях окна были установлены концевые выключатели, и в случае, если окно открылось/закрылось полностью рвут сеть.
А для связи мы используем WiFi адаптер TP-LINK с усовершенствованной антенной «Двойной квадрат» для уверенного приёма
Теперь пишем программу для управления этими приводами. Был выбран язык Python, т. к. у него нормальная поддержка Raspberry Pi и конкретно GPIO портов. Для того, чтобы открыть окно, нам нужно подать +3.3V на транзистор, который активирует реле, и то начнёт открывать окно. Чтобы его закрыть, делаем то же самое, только в это случаем наше реле подключено наоборот к приводу. Но на Raspberry мы просто подаём ток то на один порт, то на другой. Мы решили, что если температура больше 26 открываем окно в течение 1 секунды. Затем ждём 3 минуты. Если опять жарко, то открываем второе окно в течение секунды. Ждём опять 3 минуты, и делаем заново. То же самое с закрытием, только тут температура должна быть ниже 24 градусов. А вот и код:
temp.py
import RPi.GPIO as GPIO
import time
import os
import datetime
GPIO.setmode(GPIO.BOARD)
GPIO.cleanup()
GPIO.setup(31, GPIO.OUT)
GPIO.setup(33, GPIO.OUT)
GPIO.setup(35, GPIO.OUT)
GPIO.setup(37, GPIO.OUT)
#Получаем температуру
def gettemp():
if os.path.isdir("id датчика"): #Если датчик подключён, то считываем значение
tfile2=open("/sys/bus/w1/devices/id датчика")
ttext2=tfile2.read()
tfile2.close()
temp2=ttext2.split("\n")[1].split(" ")[9]
t2=float(temp2[2:])/1000
print t2
else: #если нет, то задаём дефолтное
print ('File not found')
t2==24
return t2
t2=24 #Задаём дефолтное значение для датчика
while True: вечный цикл
t2=gettemp()
if t2<24: #Если температура меньше 24, то закрываем окно в течение секунды
GPIO.output(37, 1)
print ("close1")
time.sleep(1)
GPIO.output(37, 0)
elif t2>26: #Если больше 26, то открываем окно в течение секунды
GPIO.output(35, 1)
print ("open1")
time.sleep(2)
GPIO.output(35, 0)
else: #Иначе ничего не делаем
print ("none1")
time.sleep(180)#Ждём 3 минуты
#Опять читаем температуру
t2=gettemp()
#Всё то же самое, только со вторым окном.
if t2<24:
GPIO.output(33, 1)
print ("close2")
time.sleep(1)
GPIO.output(33, 0)
elif t2>26:
GPIO.output(31, 1)
print ("open2")
time.sleep(1)
GPIO.output(31, 0)
else:
print ("none2")
#Опять ждём 3 минуты
time.sleep(180)
А теперь начинается шоу для тех, кому физика не интересна.
Установив Apache на дистрибутив Raspbian, мы в течение месяца не могли достучаться до странички из интернета. Что только не делали. Настраивали порты, открывали их, ничего не помогала. Причём в локальной сети всё работали. Потом мы узнали печальную правду: мы находимся за NAT. И услуг по выделенному IP наш оператор не предоставляет (Привет сотрудникам Регион Телекома). Перебирали много обходных методов, но ничего не выходило. Пытался сделать веб интерфейс на хостинге, но для синхронизации базы данных тоже нужен IP. Брокер IPv6 к тому времени уже закрылся. А делать VPN дорого, ведь хочется всё бесплатно. И тут решили использовать Telegram бота. Как оказалось он имеет два режима: постоянный опрос сервера и отправка сообщений прямо к нам. Первый вариант подходил, т.к. не требует от нам IP адреса. Покопавшись в интернете нашёл библиотеку: pytelegrambotapi. И принялся за написание кода. Правда выходили и проблемы. Еле найденная MySQL библиотека отказывалась писать в базу данных, но при это читала из неё всё нормально. Пришлось делать костыль: передавать данные в файл, хранящийся в ОЗУ, затем запускать bash скрипт, который считает данные и занесёт в БД.
Делаем файл config.ini, туда кидаем:
[mysql]
host = localhost
database = telegram
user = root
password = secret
Не забываем данные заменить на свои.
Создаём файл python_mysql_dbconfig.py, со следующим содержимым:
from configparser import ConfigParser
def read_db_config(filename='config.ini', section='mysql'):
""" Read database configuration file and return a dictionary object
:param filename: name of the configuration file
:param section: section of database configuration
:return: a dictionary of database parameters
"""
# create parser and read ini configuration file
parser = ConfigParser()
parser.read(filename)
# get section, default to mysql
db = {}
if parser.has_section(section):
items = parser.items(section)
for item in items:
db[item[0]] = item[1]
else:
raise Exception('{0} not found in the {1} file'.format(section, filename))
return db
Так же нам нужно создать файл python_mysql_connect2.py, с вот таким содержимым:
from mysql.connector import MySQLConnection, Error
from python_mysql_dbconfig import read_db_config
def connect():
""" Connect to MySQL database """
db_config = read_db_config()
try:
print('Connecting to MySQL database...')
conn = MySQLConnection(**db_config)
if conn.is_connected():
print('connection established.')
else:
print('connection failed.')
except Error as error:
print(error)
finally:
conn.close()
print('Connection closed.')
if __name__ == '__main__':
connect()
Теперь мы всё подготовили для работы с БД.
Отвлечёмся немного от базы данных и перейдём непосредственно к общению с ботом. Ну как обычно, пишем @BotFather, и берём у него токен. Создаём файл config.py, и пишем в него две строчки:
# -*- coding: utf-8 -*-
token = 'Ваш токен'
Я решил реализовать в боте три функции:
- Получение температуры
- Получение снимков
- Управление окнами
С первым всё просто, по запросу читаем файл с температурой, и отправляем это пользователю.
Со снимками посложнее. Я использую утилиту Motion. В её параметрах проси класть в папку в оперативной памяти снимки, ну допустим каждые 30 секунд. И делаем файлы с одинаковыми имена, и они просто заменяют друг друга. А потом по запросу отправляем файл пользователю.
Ну и третий, самый сложный модуль: управление окнами. У меня главная задача: чтобы работала автоматика, но если нужно, то мы её можем отключить. Делал я это так. Создал в оперативной памяти очередной файл. Когда мы отправляем запрос на открытие/закрытие, приоткрытие, призакрытие окна или на включение/выключение автоматики бот пишет в этот файл номер команды. Каждые пять секунд программа управления окнами считывает этот файл, и если распознаёт команду, выполняет её. После выполнение в этот же файл пишет, что всё прошло успешно. Бот опять читает файл, и уведомляет нас, что команда выполнена.
Ну а теперь исходный код. Сначала та же самая программа для открывания окон, только уже переделанная под бота(temp.py):
temp.py
import RPi.GPIO as GPIO
import time
import os
import datetime
GPIO.setmode(GPIO.BOARD)
GPIO.cleanup()
GPIO.setup(31, GPIO.OUT)
GPIO.setup(33, GPIO.OUT)
GPIO.setup(35, GPIO.OUT)
GPIO.setup(37, GPIO.OUT)
#Пишем в файл, что готовы к работе
f = open('/mnt/raw/wind', 'w')
f.write('OK')
f.close()
#Пишем, что автоматика включена
f = open('/mnt/raw/pos', 'w')
f.write('1')
f.close()
#получаем температуру
def gettemp():
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
print t2
else: #если нет, то задаём дефолтное
print ('File not found')
t2==24
return t2
#Включаем автоматику по дефолту
i=1
#Дефолтная температура
t2=24
#Читаем команды от бота
def info():
f = open('/mnt/raw/wind')
com = f.read()
f.close()
return com
#Отвечаем боту, что всё успешно
def ans():
f = open('/mnt/raw/wind', 'w')
f.write('OK')
f.close()
print ("OK")
#Анализируем команды
def rob():
c = info()
if c=="10":
GPIO.output(37, 1)
print ("close1")
time.sleep(3)
GPIO.output(37, 0)
ans()
elif c=="11":
GPIO.output(35, 1)
print ("open1")
time.sleep(2)
GPIO.output(35, 0)
ans()
elif c=="12":
GPIO.output(37, 1)
print ("close1")
time.sleep(3)
GPIO.output(37, 0)
ans()
elif c=="13":
GPIO.output(35, 1)
print ("open1")
time.sleep(1)
GPIO.output(35, 0)
ans()
elif c=="20":
GPIO.output(33, 1)
print ("close2")
time.sleep(3)
GPIO.output(33, 0)
ans()
elif c=="21":
GPIO.output(31, 1)
print ("open2")
time.sleep(3)
GPIO.output(31, 0)
ans()
elif c=="22":
GPIO.output(33, 1)
print ("close2")
time.sleep(1)
GPIO.output(33, 0)
ans()
elif c=="23":
GPIO.output(31, 1)
print ("open2")
time.sleep(1)
GPIO.output(31, 0)
ans()
elif c=="30":
global i
i=0
ans()
f = open('/mnt/raw/pos', 'w')
f.write('0')
f.close()
print('30')
global i
i=0
ans()
elif c=="31":
f = open('/mnt/raw/pos', 'w')
f.write('1')
f.close()
print('31')
global i
i=1
ans()
while True:
#Читаем и выполняем команды
rob()
#Проверяем, включена ли автоматика
if i==1:
gettemp()
if t2<24:
GPIO.output(37, 1)
print ("close1")
time.sleep(1)
GPIO.output(37, 0)
elif t2>26:
GPIO.output(35, 1)
print ("open1")
time.sleep(2)
GPIO.output(35, 0)
else:
print ("none1")
#Ожидаем 3 минуты, и в течение этого времени читаем команды
j=0
while(j<36):
rob()
time.sleep(5)
j=j+1
if i==0:
break
gettemp()
if t2<24:
GPIO.output(33, 1)
print ("close2")
time.sleep(1)
GPIO.output(33, 0)
elif t2>26:
GPIO.output(31, 1)
print ("open2")
time.sleep(1)
GPIO.output(31, 0)
else:
print ("none2")
j=0
while(j<36):
rob()
time.sleep(5)
j=j+1
if i==0:
break
Но а теперь поговорим про самого бота. Как я уже говорил, я использую библиотеку PyTelegramBotApi. Если обратиться к документации на GitHub, то можно понять что для обработки команд бот использует хендлеры. Хендлер — это событие в нашей программе, определяющие действие. В нашей случае это определенная фраза в сообщение. А действие это всё что мы можем сделать в языке python. В данном случае мы будет присылать пользователю какую-нибудь информацию пользователю или записывать команды для окон в файл. В основном наша программа состоит из этих самых хендлров и команды опроса сервера.
Но так же я сам написал и добавил ещё одно интересную вещь: блок авторизации. Ну как понятно из названия, он сделан для защиты нашей теплицы от несанкционированного доступа. Он работает просто. При первом подключение к боту он запрашивает у нас пароль. Если мы его вводим правильно, бот добавляет нас в базу данных, и при следующих подключениях нам уже авторизироваться не нужно. Бот узнаёт нас при помощи chat-id. Chat-id последнего пользователя храним в переменно, чтобы всё время не дёргать базу.
Теперь создаём файл daba.py и пишем туда вот это:
daba.py
from mysql.connector import MySQLConnection, Error
from python_mysql_dbconfig import read_db_config
import time
def getkey(): #Читаем пароль для бота
try:
dbconfig = read_db_config()
conn = MySQLConnection(**dbconfig)
cursor = conn.cursor()
cursor.execute("SELECT key2 FROM tkey where id=0")
row = cursor.fetchone()
return row
print(row)
except Error as e:
print(e)
finally:
cursor.close()
conn.close()
def sendup(): #Отправляем время запуска бота (не работает)
stime=time.time()
query = "INSERT INTO uptime(datetime, also) " \
"VALUES(now(), 20)"
args=(stime)
try:
dbconfig = read_db_config()
conn = MySQLConnection(**dbconfig)
cursor = conn.cursor()
cursor.execute(query)
row = cursor.fetchone()
return(row)
print(row)
except Error as e:
print(e)
finally:
cursor.close()
conn.close()
def getid(idi): #проверяем есть ли id пользователя в базе
query="SELECT accecpt FROM users WHERE chatid ='"+str(idi)+"'"
try:
dbconfig = read_db_config()
conn = MySQLConnection(**dbconfig)
cursor = conn.cursor()
cursor.execute(query)
row = cursor.fetchone()
#print (str(row))
if str(row)=="None":
return 0;
print (0)
else:
return 20;
except Error as e:
print(e)
#finally:
#cursor.close()
#conn.close()
def newuser(idi): #Добавляем пользователя в базу данных
query = ("INSERT INTO users SET `chatid`='12345'")
try:
dbconfig = read_db_config()
conn = MySQLConnection(**dbconfig)
cursor = conn.cursor()
cursor.execute(query)
row = cursor.fetchone()
print(row)
except Error as e:
print(e)
return(e)
finally:
cursor.close()
conn.close()
if __name__ == '__main__':
query_with_fetchone()
Так же давайте сразу сделаем ещё несколько вспомогательных скриптов. Создаём файл newuser.sh и пишем в него:
#!/bin/bash
a=`cat /mnt/raw/user`
cat /dev/null > /mnt/raw/user
mysql -u root -pkoshak << EOF
use telegram;
INSERT INTO users(chatid) VALUES('$a');
EOF
И создадим два скрипта для запуска бота и программы окон:
#!/bin/bash
i=0
while [ $i = 0 ]
do
echo New python
sleep 5
python3 bot.py
done
И ещё один:
#!/bin/bash
i=0
while [ $i = 0 ]
do
echo New python
sleep 5
python3 temp.py
done
«Зачем мы это делаем?» спросите вы. А тут дело в том, что иногда из-за нестабильного интернет соединения, или ошибки на сервера 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(commands=['auth'])
def start2(message):
if message.text[6:]==keyword:#Вырезаем пароль из сообщения
if getid(str(message.chat.id))==20:#Проверяем пароль в базе данных, если пользователь там уже есть нам вернётся код 20
bot.send_message(message.chat.id, "Вы уже авторизированы")
else:
global par
bot.send_message(message.chat.id, "Успешно", reply_markup=markup)
par=message.chat.id
#Отправляем chat-id в базу данных
f = open('/mnt/raw/user', 'w')
f.write(str(message.chat.id))
f.close()
os.system('newuser.sh')
print (message.chat.id)
print (par)
else:
bot.send_message(message.chat.id, "Неверно")
print (keyword)
print (message.text[6:])
print (message.chat.id)
# Команда /start
@bot.message_handler(commands=['start'])
def start(message):
global par
if avtor(message.chat.id)!=0:
print (par)
bot.send_message(message.chat.id, " Вы не авторизированны. Пройдите авторизацию командой /auth [пароль]", reply_markup=markup2)
else:
bot.send_message(message.chat.id, " Вы авторизированный пользователь. Наберите /help, для того, чтобы узнать список команд.")
#Команда запроса помощи - /help
@bot.message_handler(commands=['help'])
def help(message):
if avtor(message.chat.id)==0:
mas=' Данный бот управляет теплицей на моём участке. \n Список команд для помощи, в управление этим ботом: \n Получить справку - /help \n Остальное всё управляется при помощи клавиатуры :)'
bot.send_message(message.chat.id, mas, reply_markup=markup)
print (message.chat.id, message.text)
#Заменить интерфейс командной строки на клавиатуру
@bot.message_handler(commands=['show'])
def show(message):
if avtor(message.chat.id)==0:
mas='Клавиатура включена'
bot.send_message(message.chat.id, mas, reply_markup=markup)
print (message.chat.id, message.text)
#получить температуру
@bot.message_handler(regexp=" Прислать температуру")
def temp(message):
if avtor(message.chat.id)==0:
tp=get_temp()
mas=' Температура в теплице: '+str(tp)+'°C'
bot.send_message(message.chat.id, mas)
print (message.chat.id, message.text)
#прислать снимок
@bot.message_handler(regexp=" Прислать снимок")
def photo(message):
if avtor(message.chat.id)==0:
path='/mnt/raw/photo/foto.jpg' #Путь к папку со снимком
try:
f = open(path, 'rb') #Открытия файла - снимка
bot.send_photo(message.chat.id, f) #Отправка снимка
print (message.chat.id, message.text)
except:
bot.send_message(message.chat.id, "Фоток нет :(")
#Переход в меню окон
@bot.message_handler(regexp=" Управление окнами")
def windows(message):
if avtor(message.chat.id)==0:
print ("window")
print (pos())
if str(pos())[0]=='1':
bot.send_message(message.chat.id, "Ок", reply_markup=markup3)#Если автоматика включена, то выводим клавиатуру с надписью «Выключить автоматику»
else:
bot.send_message(message.chat.id, "Ок", reply_markup=markup4)#А здесь всё с точность наоборот
#Кнопка назад
@bot.message_handler(regexp=" Назад")
def windows(message):
if avtor(message.chat.id)==0:
bot.send_message(message.chat.id, "Ок", reply_markup=markup)
#Выключение автоматики
@bot.message_handler(regexp=" Выключить автоматику ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')#Открываем файл
f.write('30')#Пишем туда код команды, в данный момент это 30
f.close()#Закрываем файл
k="No"#Дефолтное значение переменной
while k[0:2]!="OK":#Проверяем ответ
time.sleep(5)#Ждём 5 секунд
f = open('/mnt/raw/wind')#Открываем файл
k = f.read()#Читаем ответ
f.close()#Закрывает
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup4)
@bot.message_handler(regexp=" Включить автоматику ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('31')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup3)
@bot.message_handler(regexp="️ Ручное управление")
def windows(message):
if avtor(message.chat.id)==0:
bot.send_message(message.chat.id, "Ок", reply_markup=markup5)
@bot.message_handler(regexp="️ Назад")
def windows(message):
if avtor(message.chat.id)==0:
if str(pos())[0]=='1':
bot.send_message(message.chat.id, "Ок", reply_markup=markup3)
else:
bot.send_message(message.chat.id, "Ок", reply_markup=markup4)
@bot.message_handler(regexp="️ Назад")
def windows(message):
if avtor(message.chat.id)==0:
bot.send_message(message.chat.id, "Ок", reply_markup=markup5)
#Бегаем по меню
@bot.message_handler(regexp=" Первое окно")
def windows(message):
if avtor(message.chat.id)==0:
bot.send_message(message.chat.id, "Ок", reply_markup=markup6)
@bot.message_handler(regexp=" Второе окно")
def windows(message):
if avtor(message.chat.id)==0:
bot.send_message(message.chat.id, "Ок", reply_markup=markup7)
@bot.message_handler(regexp="️ Открыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('11')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup6)
@bot.message_handler(regexp="️ Закрыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('10')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup6)
@bot.message_handler(regexp=" Приоткрыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('13')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup6)
@bot.message_handler(regexp=" Призакрыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('12')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup6)
@bot.message_handler(regexp="️ Открыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('21')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup7)
@bot.message_handler(regexp="️ Закрыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('20')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup7)
@bot.message_handler(regexp=" Приоткрыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('23')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup7)
@bot.message_handler(regexp=" Призакрыть окно ")
def windows(message):
if avtor(message.chat.id)==0:
f = open('/mnt/raw/wind', 'w')
f.write('22')
f.close()
k="No"
while k[0:2]!="OK":
time.sleep(5)
f = open('/mnt/raw/wind')
k = f.read()
f.close()
print(k[0:2])
bot.send_message(message.chat.id, "Успешно", reply_markup=markup7)
#Реакция на команды, не приведённые выше
@bot.message_handler(content_types=["text"])
def repeat_all_messages(message):
if avtor(message.chat.id)==0:
bot.send_message(message.chat.id, "Я не знаю такой команды. Набери /help, чтобы получить список команд")
print (message.chat.id, message.text)
#Отпрашиваем сервер на наличие новых сообщений
if __name__ == '__main__':
bot.polling()
Не забываем указать здесь id датчика, chat-id и путь к разделу в оперативной памяти. Теперь у нас почти всё готово. Качаем этот дамп, и заливаем базу данных на свой сервер, и не забываем смонтировать раздел в оперативной памяти, думаю 10 МБ хватит по горло. Запускаем два наших скрипта-стартера и радуемся. Пароль по умолчанию: telbot. Меняем его в таблице tkey базы данных.
СМС информирование
Так же сделал СМС информирование на случай перегрева. Создаём файл sms.py:
sms.py
#!/usr/bin/env python
# -*- coding: utf8 -*-
""" Автор Титов А.В. t_aleksandr_v@inbox.ru 17.02.2015 """
""" Скрипт предназначен для отправки СМС через сайт sms.ru """
""" Принимает следующие аргументы:"""
""" -i или --idsender - id пользователя на sms.ru"""
""" -t или --to - номер телефона получателя в формате 79219996660"""
""" -s или --subject - текст сообщения на латинице"""
from urllib2 import urlopen
from optparse import OptionParser
def sendsms(idsender,subject,to):
subject = subject.replace(" ","+")
url="http://sms.ru/sms/send?api_id=%s&text=%s&to=%s" %(idsender,subject,to)
res=urlopen(url)
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-i", "--ваш ключ", dest="idsender", default="ваш ключ", help="ID user on sms.ru", metavar="IDSENDER")
parser.add_option("-t", "--ваш телефон", dest="to", default="ваш телефон", help="to telephone number", metavar="TO")
parser.add_option("-s", "--temperatyra 32", dest="subject", default="Jara tut, otkroy okno", help="Name of subject", metavar="SUBJECT")
(options, args) = parser.parse_args()
sendsms(options.idsender,options.subject,options.to)
Регистрируемся на sms.ru и берём там API-key в разделе для программистов. Так же не забываем указать в скрипте ваш номер телефона.
В программе для управления окон объявляем переменную:
Vr=0
Затем вставляем в вечный цикл этот код:
d = datetime.today()
V = d.strftime('%H')
V = int(V)
if (t2>32 and Vr!=V):
print (V)
Vr=V
os.system('/home/samba/sms.py')
В данный момент температура порога 32, смс будут отправляться в случае высокой температуры раз в час, пока она не спадёт.
P.S. В планах на будущее установить управляемый обогреватель и сделать автоматический полив.
Спасибо всем тем, кто дочитал до конца.