Дача, USB-модемы, две малины, или сказ о том, как я температуру в доме проверял.

  • Автор
Добрый день! Хочу рассказать вам про свои приключения и поиски надежного решения для удаленного мониторинга температуры помещения, наблюдения за окружающим миром и включения/выключения устройств.

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

Дано: 2 дачи.
Первая - с газовым отоплением, и основная задача - поймать момент снижения температуры (ака потухший фитиль), чтобы осталось время приехать и зажечь его, не дать трубам разорваться от замерзшей в них воды. Интернет - gprs, качество приема - устойчивое.

Вторая - без отопления, только электрические тены. Тут необходимо удаленное включение устройств(тенов), поддержание комфортной температуры для сна. Интернет - отсутствует, gsm сигнал есть, однако работает скверно.

детали под катом


Так получилось, что у меня дома завалялась малинка и usb gprs свисток. Решил начать со второй дачи, дабы интеграцию с web сервисами оставить на потом.
Общение с внешним миром из-за отсутствия Интернет - только по смс.
Основная последовательность действий:
1) установка debian os
2) изменение modeswitch usb свистка, на режим модема
3) написание программы для работы с приемом, парсингом и отправкой сообщений.
Язык python, библиотека для общения с модемом - gammu, датчик температуры bmp085, LCD дисплей, и два простых реле.

Основные функции: Включение питания (пин 4), Включение второго устройства (пин 17), получение сведений о температуре и их отправка, переход в режим поддержания температуры в определенном интервале.

Самое интересное, код:
# -*- coding: utf-8 -*-
import gammu
import time
import RPi.GPIO as GPIO
import Adafruit_BMP.BMP085 as BMP085
import lcddriver
import os
from datetime import datetime
from subprocess import call


f = open('/var/log/sms','a')
f.write(str(datetime.now()) + ' System started\n')
f.close()

GPIO.setmode(GPIO.BCM)
pinList = [4, 17]
sensor = BMP085.BMP085()
lcd = lcddriver.lcd()

#Обьявляем телефоны, с которых мы будем обрабатывать смски
cellphones = ['+7926XXXXX','+7926XXXXXX']
currcommand = ''

for i in pinList:
GPIO.setup(i, GPIO.OUT)
GPIO.output(i, GPIO.HIGH)


sm = gammu.StateMachine()
sm.ReadConfig()
sm.Init()
sm.GetSMSStatus()

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

def delete_all_sms():
status = sm.GetSMSStatus()
remain = status['SIMUsed'] + status['PhoneUsed'] + status['TemplatesUsed']
start = True
while remain > 0:
sms = sm.GetNextSMS(Start = True, Folder = 0)
remain = remain - len(sms)
for m in sms:
sm.DeleteSMS(Location = m['Location'], Folder = 0)

#функция чтения смс, с удалением после прочтения.
def retSMS():
start = True
sms=[{'Number':0,'Text':2},{'Number':0,'Text':2}]
while 1:
try :
if start:
sms = sm.GetNextSMS(Start = True, Folder=0)
start = False
else:
sms = sm.GetNextSMS(Location = sms[0]['Location'], Folder=0)
except gammu.ERR_EMPTY:
break

try:

delete_all_sms()
except gammu.ERR_EMPTY:
a=1
return(sms[0]['Number'],sms[0]['Text'])

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

def sndSMS(number,smstext):
message = {
'Text': smstext,
'SMSC': {'Location': 1},
'Number': number,
}
try:
sm.SendSMS(message)
except gammu.ERR_UNKNOWN:
f = open('/var/log/sms','a')
f.write(str(datetime.now()) + ' Failed to send sms\n')
f.write(str(datetime.now()) + ' Rebooting in 3.5 minutes...\n')
print ("failed to send")
time.sleep(200)
f.write(str(datetime.now()) + ' Rebooting...\n')
f.close()
os.system("sudo shutdown -r now")


#read temperature
def readtemp():
curtemp=sensor.read_temperature()
return curtemp


#Основная функция расшифровки сообщений, обработки заданий.
def parscom(detSms):
currcommand=''
if detSms[0] in cellphones:
if detSms[1]=='On':
GPIO.output(4, GPIO.LOW)
sndSMS(detSms[0], 'Otoplenie on')
currcommand='On'
if detSms[1]=='Poliv':
GPIO.output(17, GPIO.LOW)
sndSMS(detSms[0], 'Poliv ON')
currcommand='PolivOn'
if detSms[1]=='PolivOff':
GPIO.output(17, GPIO.HIGH)
sndSMS(detSms[0], 'Poliv Otkluchen')
currcommand='PolivOff'
if detSms[1]=='Off':
GPIO.output(4, GPIO.HIGH)
sndSMS(detSms[0], 'Otoplenie Off')
currcommand='Off'
if detSms[1]=='Temp':
print readtemp()
sndSMS(detSms[0], 'Temp: ' + str(readtemp()))
if detSms[1].split()[0]=='Set':
temp=detSms[1].split()[1]
GPIO.output(4, GPIO.LOW)
currcommand='Set ' + temp
sndSMS(detSms[0], 'Night mode On. Temperature set: ' + str(temp))
return currcommand

#Реализация функции поддержания температуры.
def otoplenie_night(settemp):
curtemp=readtemp()
try:
if curtemp>int(settemp)+0.5:

GPIO.output(4, GPIO.HIGH)
if curtemp
GPIO.output(4, GPIO.LOW)
except:
GPIO.output(4, GPIO.HIGH)


#Основной цикл - отправка смс при включении, вызов функций чтения смс, парсинга, и вывода на lcd дисплей.
sndSMS('+7926XXXXXX', 'Cucmema Pa6omaem')
while 1:
detSms=retSMS()
newcommand = parscom(detSms)
lcd.lcd_display_string("TEMnEPATYPA: " + str(readtemp()) + " C" , 1)
if currcommand != newcommand and newcommand != '':
currcommand=newcommand
lcd.lcd_display_string("KOMAHDA: " , 2)
lcd.lcd_display_string("KOMAHDA: " + currcommand , 2)
try:
if currcommand.split()[0]=='Set':
otoplenie_night(currcommand.split()[1])

except IndexError:
a=0
time.sleep(5)




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

Работает по крону 2 скритпа:
1) делаем фото окружающей природы с камеры подключенной по usb к малине и отправляем на список почтовых адресов.
2) вызываем бесплатный интернет-сервис по отправке смс сообщений.
+ Запускается gammu демон, который автоматически подключается к интернету при загрузке малины.

Код получения картинки и отправки по почте:

from smtplib import SMTP_SSL
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders
import os


#Меряем температуру (Датчик DS18B20)
def readtemp():
tfile=open("/sys/bus/w1/devices/28-00000633a133/w1_slave")
ttext=tfile.read()
tfile.close()
temp=ttext.split("\n")[1].split(" ")[9]
temperature=float(temp[2:])/1000
return temperature

temperatur=str(readtemp())


#Делаем фото
os.system ("fswebcam -r 1024x768 -S 15 /home/pi/pics/static/temp.jpg")

#Путь для аттача
filepath = "/home/pi/pics/static/temp.jpg"
basename = os.path.basename(filepath)
#куда отправлять письма:
address = ['XXX@gmail.com','XXXX@list.ru','XXX@mail.ru']

Наш аккаунт, откуда отправляем
adressfrom='XXX@yandex.ru'
# Compose attachment
part = MIMEBase('application', "octet-stream")
part.set_payload(open(filepath,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % basename)

# Compose message
msg = MIMEMultipart()
msg['From'] = adressfrom
msg['To'] = ", ".join(address)
msg['Subject'] = 'A vot i temperatura ' + temperatur
msg['Body']='Temperatura'
msg.attach(part)


# Send mail
smtp = SMTP_SSL()
smtp.connect('smtp.yandex.ru')
smtp.login(adressfrom, 'PASSWORD')
smtp.sendmail(adressfrom, address, msg.as_string())
smtp.quit()

В результате получаем на почту такую красивую картинку, и на душе как-то становится теплее.




А это код отправки СМС с использованием бесплатного веб-сервиса:

import requests
import os

#Читаем температуру
def readtemp():
tfile=open("/sys/bus/w1/devices/28-00000633a133/w1_slave")
ttext=tfile.read()
tfile.close()
temp=ttext.split("\n")[1].split(" ")[9]
temperature=float(temp[2:])/1000
return temperature

temperatur=str(readtemp())
#вызываем веб сервис, для формирования смс.
r = requests.get('http://sms.ru/sms/send?api_id=ID_API&to=7926NUMBER4&text=Temperatura+'+ temperatur)
q = requests.get('http://sms.ru/sms/send?api_id=ID_API&to=7910NUMBER&text=Temperatura+'+ temperatur)



Вскоре обнаружились сбои, связанные с зависанием малины после нескольких дней работы, несмотря на работу вотчдогов. Победил это просто, ежедневным ребутом. И, как я писал выше, с тех пор обе системы работают без нареканий. За прошедшую зиму благодаря системе удалось дважды спасти отопление дачи, вовремя получив заветную смс.

Спасибо за прочтение статьи! Некоторые детали я пропустил в своем повествовании, но готов ответить на любые возникшие вопросы :)

Комментарии:

alfacom
У меня небольшая куча вопросов.



Фото природы — просто природа на даче красивая?)



Код Питоновский?



Многие популярные LCD-дисплеи поддерживают кириллические символы. Ваш не поддерживал, или лень возиться было?



сбои связанные с зависанием малины


Очень интересно. Какую малинку(и) использовали? Зависания были на обоих малинках?



код отправки СМС используя бесплатный веб сервис


Сразу подумал о sms.ru. Прочел код и убедился в своем предположении)
Rampage4
Фото, да насамом деле просто мониторить, что стекла в доме не разбили, соседи приехали/уехали :)

Код да, все на питоне. Очень простой и понятный для понимания язык. После увлечения малинкой, начал даже на работе его продвигать.

Про Lcd — да, просто не хотелось убивать времени больше, чем было необходимо для конкретных задач.



Очень интересно. Какую малинку(и) использовали? Зависания были на обоих малинках?
Raspberry PI Model B. Да висли обе, причем с некоторой зависмостью от зоны приема gsm. Запускаю для теста дома (москва) — неделю работает без проблем. На даче — через три дня уходит «в себя».



Сразу подумал о sms.ru. Прочел код и убедился в своем предположении)
Реально, очень крутой сервис, учитывая бесплатность для разработчиков. Работает без сбоев пол года.
amf
Очень интересно почитать. спасибо!

Подскажите, почему было решено делать на Raspberry?

Первый проект (да и второй тоже) точно бюджетнее было сделать на Arduino.
Rampage4
Бюджетнее ли при наличии usb модемов? :-)



При оценке вариантов, конечно смотрел на трудоемкость и стоимость.

Трудоемкость для меня победила малина: возможность использования Python, и наличия полноценной OS.

Стоимость: смотрел на стоимость GSM шилдов в поднебесной… и видел ценники за 600+ рублей. Малину(вторую) взял за 1к рублей «с рук». Потому получилось по вполне адекватной цене, и дешевле gsm розеток :-)
amf
Спасибо за ответ.



да, видимо, возможность использования usb модемов — это серьезный плюс в копилку малины. Прямо да, реально. Да еще и вторая малина за дешево ))



тоже хочу что-то подобное сделать, смотрел в сторону Arduino + какой-нить GSM-модуль типа m590e. из китая, естественно. И там пока бюджет всего в 1к. ))
Rampage4
Ну, вместо малины оранж пи ван можно взять. Одноплатник за 9.99 usd.

Я вот в конкурсе третью не выиграл… пришлось оранж взять :))) уже доставили… начинаю теперь новые экспиременты на нем.



Ардуину, кстати про мини можешь взять. 1.45usd стоит в забугорье. Только ножки припаять надо будет и усб уарт переходник для записи скетчей.
amf
orange pi — интересная штука. )

надо будет попробовать.



сначала я тоже на про мини смотрел, но потом «открыл» nano. цена чуть больше, но и паять не надо, и программировать проще. и разъем знакомый.

Для написания комментариев необходимо зарегистрироваться