Датчик температуры Raspberry Pi с выводом на ЖК-экран

Датчик температуры 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, представленная ниже:

Схема подключения датчика температуры к Raspberry Pi

Когда схема собрана корректно, проверьте конфигурацию с помощью тестового кода. Загрузить его можно с официальной страницы здесь. Код доступен на Python и на C — мы будем работать с Python.

При удалённой работе можно скачать код на свой компьютер, а затем передать его на Raspberry Pi через FileZilla.

Для проверки схемы запустите файл «18_thermistor.py». Вывод должен быть приблизительно таким.

Результат работы скрипта термистора

Использование ЖК-дисплея Raspberry Pi

Используемый дисплей подключается всего четырьмя проводами. Температурный датчик при этом остаётся подключённым. Подсоедините ЖК-дисплей по приведённой ниже схеме от SunFounder.

Дисплей и температурный датчик используют общие контакты «SDA1» и «SCL1». На этих контактах всё работает корректно.

Схема подключения ЖК-дисплея к Raspberry Pi

Для вывода текущей температуры на дисплей создайте новую папку, к примеру «LCDTemp», и перенесите в неё два выделенных на рисунке файла из каталога с кодом SunFounder. Это библиотеки, предназначенные именно для оборудования из набора SunFounder Kit (совместимость с другими датчиками не тестировалась).

Файлы библиотек SunFounder

Имея эти библиотеки, можно приступать к написанию кода для отображения текущей температуры на экране:

#*****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), как показано на рисунке:

Создание приложения в aWhere

После создания приложения вы получите ключ «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

Получение исторических данных о погоде

Теперь, когда поле успешно создано, можно извлечь исторические метеоданные для данного географического региона. Документация 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 расскажем в следующих материалах.