Датчик температуры Raspberry Pi с выводом на ЖК-экран
Выведем на ЖК-дисплей текущую температуру окружающей среды и среднее значение за конкретный день, задействовав Raspberry Pi.
Что нам понадобится?
Необходимое оборудование:
Raspberry Pi 3 Модель B+ (примерно $60)
Аналоговый датчик температуры (примерно $8)
Модуль преобразователя AD/DA (примерно $9)
ЖК-экран LCD1602 (примерно $12)
Перечисленные компоненты позволят показать текущую температуру воздуха и среднее значение за выбранный день на ЖК-экране при помощи Raspberry Pi, aWhere API и библиотек SunFounder.
Датчик температуры Raspberry Pi
В данном уроке задействован Sensor Kit V2.0 от SunFounder, включающий аналоговый температурный сенсор и модуль PCF8591 — устройство для сбора аналоговых данных. За основу взята схема подключения от SunFounder, представленная ниже:
Когда схема собрана корректно, проверьте конфигурацию с помощью тестового кода. Загрузить его можно с официальной страницы здесь. Код доступен на Python и на C — мы будем работать с Python.
При удалённой работе можно скачать код на свой компьютер, а затем передать его на Raspberry Pi через FileZilla.
Для проверки схемы запустите файл «18_thermistor.py». Вывод должен быть приблизительно таким.
Использование ЖК-дисплея Raspberry Pi
Используемый дисплей подключается всего четырьмя проводами. Температурный датчик при этом остаётся подключённым. Подсоедините ЖК-дисплей по приведённой ниже схеме от SunFounder.
Дисплей и температурный датчик используют общие контакты «SDA1» и «SCL1». На этих контактах всё работает корректно.
Для вывода текущей температуры на дисплей создайте новую папку, к примеру «LCDTemp», и перенесите в неё два выделенных на рисунке файла из каталога с кодом SunFounder. Это библиотеки, предназначенные именно для оборудования из набора SunFounder Kit (совместимость с другими датчиками не тестировалась).
Имея эти библиотеки, можно приступать к написанию кода для отображения текущей температуры на экране:
#*****dispTemp.py*****#
from decimal import Decimal
import RPi.GPIO as GPIO
import PCF8591 as ADC
import math
import time
import LCD1602 as LCD
tempPin = 11 # temperature D0 pin
GPIO.setmode(GPIO.BOARD) # reference pins using BOARD numbers
# *****Initialize Pins*****#
def setup():
ADC.setup(0x48) # set up analog converter
GPIO.setup(tempPin, GPIO.IN) # set pin to input
LCD.init(0x27, 1) # init(slave address, background light)
def loop():
while True:
analogVal = ADC.read(0) # read temperature sensor value
# Calculations to convert to Celsius, from SunFounder
Vr = 5 * float(analogVal) / 255
Rt = 10000 * Vr / (5 - Vr)
temp = 1 / (((math.log(Rt / 10000)) / 3950) + (1 / (273.15 + 25)))
temp = Decimal(temp - 273.15) # convert to Decimal Type
temp = round(temp, 1) # round to 1 decimal point
LCD.write(0, 0, 'Temp: {} C'.format(temp)) # write to top row and farthest left column of LCD
time.sleep(1) # update every second
# *****MAIN*****#
if __name__ == '__main__':
try:
setup()
loop()
except KeyboardInterrupt:
pass
Если все элементы соединены правильно, приведённый выше код выведет на дисплей результат, аналогичный тому, что показан на фотографии ниже (конкретное значение зависит от температуры в помещении):
Получение исторических данных погоды с использованием API aWhere
Наиболее доступный бесплатный API для получения средних исторических температур по конкретной точке на карте — это aWhere. Через aWhere можно запрашивать разнообразные архивные метеоданные.
Бесплатную учётную запись можно зарегистрировать на сайте aWhere здесь. После регистрации откройте «Моя учетная запись» (англ. - My Account) в правом верхнем углу и перейдите в раздел «Мои приложения» (англ. - My apps). Там нажмите синюю кнопку «Добавить новое приложение» (англ. - Add a new App), как показано на рисунке:
После создания приложения вы получите ключ «Consumer Key» и «Consumer Secret» — они понадобятся для получения токена аутентификации в коде ниже.
Создание поля
Складывается впечатление, что сервис aWhere ориентирован преимущественно на агропромышленную сферу, поэтому для указания местоположения и получения температурных данных необходимо «добавить поле» (англ. - add a field) в своё приложение.
Документация по созданию поля доступна по ссылке. Поначалу были опробованы два подхода — через «requests» и «urllib», — однако заставить их работать не удалось. Единственный рабочий пример на Python обнаружился в разделе ответов здесь, и именно он лёг в основу приведённого ниже кода:
#*****addField.py*****#
import json
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
url = 'https://api.awhere.com/v2/fields'
consumer_key = '' # key
consumer_secret = '' # secret
# body of request, change to wherever you would like
body = {
"id": "CN_Tower",
"name": "Toronto",
"farmId": "accr",
"centerPoint": {
"latitude": 43.642465, # can get these from Google maps
"longitude": -79.386488
}
}
# get Authentication token
client = BackendApplicationClient(client_id = consumer_key)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url='https://api.awhere.com/oauth/token', client_id=consumer_key, client_secret=consumer_secret)
# post body to url
client = OAuth2Session(consumer_key, token=token)
field_response = client.post(url, json=body)
print(field_response.json())
Если поле добавлено успешно, после запуска кода вы увидите примерно такой результат (в зависимости от указанного местоположения):
Получение исторических данных о погоде
Теперь, когда поле успешно создано, можно извлечь исторические метеоданные для данного географического региона. Документация aWhere доступна здесь.
Этот этап достаточно прост: код ниже возвращает среднюю температуру за текущий день, рассчитанную по данным последних 10 лет.
#*****histWeather.py*****#
import requests, json, base64
id = 'CN_Tower' # field id
date = '05-23' # month and day that you would like 10 year average for
key = ''
secret = ''
# *****Get aWhere security token*****#
def getToken():
combination = key+':'+secret.encode()
auth = base64.b64encode(combination).decode('utf8')
credential = auth
response = requests.post('https://api.awhere.com/oauth/token',
data='grant_type=client_credentials',
headers={'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic {}'.format(credential)}).json()
if 'access_token' and 'expires_in' in response.keys():
print(response['access_token'])
return response['access_token']
else:
raise ValueError(response)
token = getToken() # get auth token
headers = {"Authorization": "Bearer " + token,
"Content-Type": "application/json"}
response = requests.get('https://api.awhere.com/v2/weather/fields/'+id+'/norms/'+date, headers=headers)
data = response.json()
print(str(data['meanTemp']['average']))
print(response)
Вывод должен выглядеть приблизительно так:
Число 15 на рисунке — это средняя температура в градусах Цельсия.
Собираем всё вместе
Итак, у нас есть текущая температура воздуха и среднее историческое значение — осталось объединить всё и вывести на ЖК-дисплей.
Код обновляет температуру окружающей среды ежесекундно, тогда как среднее значение обновляется лишь раз в сутки. Сравнение дня выполняется через переменную-счётчик «currDay»:
#*****LCDTemp.py*****#
from decimal import Decimal
import RPi.GPIO as GPIO
import PCF8591 as ADC
import math
import time
import LCD1602 as LCD
import requests, json, base64, datetime
tempPin = 11 # temperature D0 pin
GPIO.setmode(GPIO.BOARD) # reference pins using BOARD numbers
key = '' # Consumer Key
secret = '' # Consumer Secret
# *****Initialize Pins*****#
def setup():
ADC.setup(0x48) # set up analog converter
GPIO.setup(tempPin, GPIO.IN) # set pin to input
LCD.init(0x27, 1) # init(slave address, background light)
# *****Main Loop, sets temperatures*****#
def loop():
currDay = 0 # use currDay as variable to keep track of last numeric day
while True:
now = datetime.datetime.now() # create datetime object called now
if currDay == now.day: # if currDay and now.day are equal, only update ambient temperature
analogVal = ADC.read(0) # read temperature sensor value
# Calculations to convert to Celsius, from SunFounder
Vr = 5 * float(analogVal) / 255
Rt = 10000 * Vr / (5 - Vr)
temp = 1 / (((math.log(Rt / 10000)) / 3950) + (1 / (273.15 + 25)))
temp = Decimal(temp - 273.15) # convert to Decimal Type
temp = round(temp, 1) # round to 1 decimal point
LCD.write(0, 0, 'Temp: {} C'.format(temp)) # write to top row and farthest left column of LCD
time.sleep(1) # update every second
else: # if date has changed
avgTemp = getHistTemp(now.strftime('%m-%d')) # get average historical temperature for that day
avgTemp = round(Decimal(avgTemp), 1) # convert to decimal and round
LCD.write(0, 1, 'Avg Temp: ' + str(avgTemp) + ' C') # write to second row of lcd
currDay = now.day # update current day
# *****Get aWhere security token*****#
def getToken():
combination = key + ':' + secret.encode()
auth = base64.b64encode(combination).decode('utf8')
credential = auth
response = requests.post('https://api.awhere.com/oauth/token',
data='grant_type=client_credentials',
headers={'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic {}'.format(credential)}).json()
if 'access_token' and 'expires_in' in response.keys(): # if response contains access token
print(response['access_token'])
return response['access_token'] # return access token
else:
raise ValueError(response)
# ***** use aWhere to get historical temperature for certain day*****#
def getHistTemp(date):
token = getToken()
headers = {"Authorization": "Bearer " + token,
"Content-Type": "application/json"}
response = requests.get('https://api.awhere.com/v2/weather/fields/Toronto/norms/' + date, headers=headers)
data = response.json()
return (data['meanTemp']['average'])
# *****MAIN*****#
if __name__ == '__main__':
try:
setup()
loop()
except KeyboardInterrupt:
pass
В коде расставлены поясняющие комментарии, а итоговый результат должен выглядеть примерно так, как изображено ниже:
На этом пока всё. О других проектах на Raspberry расскажем в следующих материалах.