От метеостанции нужны были следующие функции:
- отображение температуры
- отображение графика атмосферного давления
- прогноз дождя
- синхронизация времени (в случае обычной метеостанции, по DCF77, если уж на устройстве есть часы, они должны показывать точное время)
Из покупных, по сочетанию «дизайн-цена-функции» не понравилась ни одна — либо нет одного, либо другого, либо слишком громоздко и дорого. В итоге решено было задействовать Raspberry Pi с TFT-экраном, и сделать те функции, которые нужны.
Получилось примерно так:
Подробности реализации и готовый проект под катом.
Получение данных погоды
Первое, с чем нужно было определиться — это получение данных погоды. Здесь есть 2 варианта, либо использовать свои датчики, либо брать погоду из интернета. Первое интереснее, но есть несколько «но»:
- Сделать датчик «абы как» несложно, но сделать датчик хорошо, чтобы он например год работал от одного комплекта батареек, задача уже не столь тривиальная. Есть конечно сейчас и малопотребляющие процы, и радиомодули, но потратить на это месяц было бы лень.
- Нужно заморачиваться с корпусом, влагозащитой и прочими мелочами (3д-принтера у меня нет).
- Балкон выходит на солнечную сторону, так что погрешность измерения температуры в первую половину дня была бы слишком большой.
Альтернативным вариантом была покупка готового метеомодуля с датчиками для Raspberry Pi.
Увы, поиск показал что в продаже есть всего 2 варианта:
— Raspberry Pi sense hat
Плата имеет «на борту» термометр, барометр, датчик влажности, гироскоп и акселерометр — но чем думали разработчики, ставя такой «экран» 8х8 светодиодов, непонятно — ничего внятного на нем вывести нельзя. Желаю разработчикам этого модуля всю жизнь UI под матрицу 8х8 писать :)
— Raspberry Pi weather hat
Ничего кроме светодиодов здесь нет вообще.
В общем, как ни странно, но нормального готового шилда для метеостанции с хорошим экраном и хорошим набором датчиков так никто и не сделал. Краудсорсеры, ау — рыночная ниша пропадает :)
В итоге, не паримся и делаем по-простому — берем погоду из Интернета и выводим на обычный TFT. Как подсказал гугл, самое развитое API сейчас у https://openweathermap.org/api, его и будем использовать.
В комментариях был вопрос про точность интернет-данных. Как можно видеть в коде ниже, для вывода температуры и атмосферного давления используется запрос на получение текущих (current weather data), а не прогнозируемых данных. Их точность можно считать вполне достаточной для бытовых целей, более того, скорее всего она даже выше, чем точность уличного термометра/датчика, размещенного за окном или на балконе.
Регистрация
Для получения данных погоды с openweathermap нужен ключ, его можно получить бесплатно, зарегистрировавшись на вышеупомянутом сайте. Ключ выглядит примерно так «dadef5765xxxxxxxxxxxxxx6dc8». Большинство функций доступны бесплатно, платные API нам не понадобятся. Для бесплатных функций есть ограничение на 60 запросов в минуту, нам этого достаточно.
Чтение данных
Чтение данных весьма просто благодаря библиотеке pyowm.
Получение погоды на данный момент (Python):
import pyowm
owm = pyowm.OWM(apiKey)
observation = owm.weather_at_coords(lat, lon)
w = observation.get_weather()
dtRef = w.get_reference_time(timeformat='date')
t = w.get_temperature('celsius')
temperatureVal = int(t['temp'])
p = w.get_pressure()
pVal = int(p['press'])
Получение прогноза погоды для отображения осадков:
fc = owm.three_hours_forecast_at_coords(lat, lon)
rain = fc.will_have_rain()
snow = fc.will_have_snow()
rains = fc.when_rain()
На выходе получаем массив данных со списком дождей и их интенсивностью. Несмотря на название функции three_hours_forecast_at_coords, дожди прописаны на 2-3 дня вперед.
Можно использовать GET-запросы напрямую, например так. Это может пригодиться, например при портировании кода на MicroPython под ESP.
Получение координат пользователя
Как можно видеть выше, для получения данных нужны широта и долгота. Получение координат также весьма просто, и делается в 3 строчки кода:
import geocoder
g = geocoder.ip('me')
lat = g.latlng[0]
lon = g.latlng[1]
UI
Собственно, самая сложная часть. На Raspberry Pi используется TFT-дисплей от Adafruit, поддерживающий систему команд ILI9340. Библиотеки под него найти несложно, однако отлаживать код на Raspberry Pi не очень удобно. В итоге было принято решение написать высокоуровневый набор контролов, которых нужно было всего 3 — изображения, текст и линии. При запуске на Raspberry Pi контрол будет рисовать себя на TFT, при запуске на десктопе будет использоваться встроенная в Python библиотека tkinter. В итоге, код будет работать везде — и на Raspberry Pi, и на Windows, и на OSX.
Код одного контрола выглядит примерно так:
class UIImage:
def __init__(self, image = None, x = 0, y = 0, cId = 0):
self.x = x
self.y = y
self.width = 0
self.height = 0
self.cId = cId
self.tkID = None
self.tftImage = None
self.tkImage = None
self.useTk = utils.isRaspberryPi() is False
if image is not None:
self.setImage(image)
def setImage(self, image):
width, height = image.size
if self.useTk:
self.tkImage = ImageTk.PhotoImage(image)
self.tftImage = image
self.width = width
self.height = height
def draw(self, canvas = None, tft = None):
if tft != None:
tft.draw_img(self.tftImage, self.x, self.y, self.width, self.height)
elif canvas != None and self.tkImage != None:
if self.tkID == None or len(canvas.find_withtag(self.tkID)) == 0:
self.tkID = canvas.create_image(self.x, self.y, image=self.tkImage , anchor=tkinter.NW)
else:
canvas.itemconfigure(self.tkID, image=self.tkImage)
Класс «FakeTFT» создает обычное окно программы:
class FakeTFT:
def __init__(self):
self.tkRoot = tkinter.Tk()
self.tkRoot.geometry("500x300")
self.screenFrame = tkinter.Frame(self.tkRoot, width=330, height=250, bg="lightgray")
self.screenFrame.place(x=250 - 330 / 2, y=5)
self.tkScreenCanvas = tkinter.Canvas(self.tkRoot, bg = 'white', width = 320, height = 240, highlightthickness=0)
self.tkScreenCanvas.focus_set()
self.tkScreenCanvas.place(x=250 - 320 / 2, y=10)
self.controls = []
def draw(self):
for c in self.controls:
c.draw(self.tkScreenCanvas)
Класс «LCDTFT» использует «настоящий» дисплей (фрагмент кода):
class LCDTFT:
def __init__(self, spidev, dc_pin, rst_pin=0, led_pin=0, spi_speed=16000000):
# CE is 0 or 1 for RPI, but is actual CE pin for virtGPIO
# RST pin. 0 means soft reset (but reset pin still needs holding high (3V)
# LED pin, may be tied to 3V (abt 14mA) or used on a 3V logic pin (abt 7mA)
# and this object needs to be told the GPIO and SPIDEV objects to talk to
global GPIO
self.SPI = spidev
self.SPI.open(0, 0)
self.SPI.max_speed_hz = spi_speed
self.RST = rst_pin
self.DC = dc_pin
self.LED = led_pin
self.controls = []
def draw(self):
for c in self.controls:
c.draw(tft = self)
При инициализации автоматически выбирается нужный дисплей, в зависимости от того, где запускается программа:
def lcdInit():
if utils.isRaspberryPi():
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
DC = 25
LED = 18
RST = 0
return LCDTFT(spidev.SpiDev(), DC, RST, LED)
else:
return FakeTFT()
Все это позволяет полностью абстрагироваться от «железа», и писать код типа такого:
self.labelPressure = libTFT.UILabel("Pressure", 18,126, textColor=self.tft.BLACK, backColor=self.tft.WHITE, fontS = 7)
self.tft.controls.append(self.labelPressure)
self.labelRain = libTFT.UILabel("Rain", 270,126, textColor=self.tft.BLUE, backColor=self.tft.WHITE, fontS = 7)
self.tft.controls.append(self.labelRain)
Собственно UI выглядит так:
На экране отображаются текущая температура, график атмосферного давления за сегодняшний день (в следующей версии будет добавлен график температуры), также в случае прогноза дождя, его время отмечается на графике вертикальной синей чертой (на данной картинке дождей нет). Также выводятся время последнего обновления данных и IP-адрес, если понадобится подключиться к устройству.
Желающие ознакомиться с исходником подробнее, могут посмотреть его на guthub.
Установка на Raspberry Pi
Для тех, кто не хочет заморачиваться описанным выше, короткая инструкция по установке под спойлером.
git clone github.com/dmitryelj/RPi-Weather-Station.git
— Если не установлен Python3, ставим:
sudo apt-get install python3
— Ставим дополнительные библиотеки (они нужны для работы с дисплеем):
sudo pip3 install numpy pillow spidev
— Добавляем в автозапуск (sudo nano /etc/rc.local)
python3 /home/pi/Documents/RPi-Weather-Station/weather.py &
— Пробуем запустить
python3 weather.py
Если все работает, то перезагружаемся (sudo reboot) и пользуемся.
В плане добавить еще что-нибудь полезное, например отображение карты облачности, API на openweathermap для этого есть.
Продолжение следует.
Комментарии (57)
Bonio
23.09.2017 17:18+2А при чем тут DCF77?
DmitrySpb79 Автор
23.09.2017 18:27При том, что если рассматривать не wifi-решение, то метеостанция должна иметь возможность приема DCF (впрочем у многих это есть, Oregon например). При наличии Wifi это разумеется, неактуально.
Bonio
23.09.2017 18:30+1У вас же тут это не реализовано? Да и смысл в DCF77, когда устройство и так сетевое, проще в таком случае синхронизировать время по NTP.
DmitrySpb79 Автор
23.09.2017 18:33Имелось в виду, что когда я искал обычные метеостанции, то выбирал только среди моделей с DCF, а это несколько сужало выбор. По WiFi это некритично, разумеется.
Bonio
23.09.2017 18:38Понятно. Просто так написано, что я подумал, что от самодельной метеостанции требуется DCF77, поэтому и не понял, зачем. Так то DCF77 модули тоже есть на ebay, для всяких оффлайн самоделок.
ximik666
23.09.2017 18:55+2Моя реализация домашней метеостанции:
- ESP8266 с датчиками влажности и температуры стоят по комнатам
- на домашнем сервере крутиться mosquitto (MQTT) и парочка скриптов на Python
- старый планшет (убитая батарейка), на экран которого с помощью приложения выводятся показания датчиков
Фотографии
DmitrySpb79 Автор
23.09.2017 18:57Спасибо, интересно. Кстати, сколько ESP от батарейки живет?
PS: Порадовал значок «в туалете нет осадков» :)ximik666
23.09.2017 19:04+1Это значит в туалете нет протечек;)
ESP отправляет и принимает показания раз в 5 минут, потом уходит в глубокий сон, но при этом дисплей продолжает отображать информацию. При такой работе на старых аккумуляторах живёт неделю.DmitrySpb79 Автор
23.09.2017 19:07Я бы в таком случае отказался от дисплея, все равно он мелкий и не особо читабелен имхо.
А в целом, потому и не хочу возиться с самодельными датчиками — каждую неделю менять/заряжать батарейки лениво, а делать специально на малопотребляющем железе, это сильно заморачиваться надо. Хотя валяются дома 2 модема от Lora, надо бы как-нибудь задействовать.ximik666
23.09.2017 19:09Да про дисплей до меня уже дошло после того, как поставил и собрал все. А потом снимать их уже не стал.
А тут я ставлю на зарядку, там сразу зарядка от микроюсб.
Bonio
23.09.2017 19:08Неделя это очень мало для датчика. Может имеет смысл убрать дисплей? Тем более, если подсветка включена постоянно.
Barnaby
24.09.2017 06:10+1Кстати, сколько ESP от батарейки живет?
Я насчитал 8 месяцев, но вольтметром это такое а повесить ADC на акб я не догадался при сборке. Пока 25-37 дней работают. ESP тратит 255 мс на включение, ~130 на подключение к wifi и ~40 на отправку данных. Потребление с полного акб через DD0503MA было 65 mA в работе и 0.05 mA в deepsleep.
dmitryrf
24.09.2017 23:59+1Какая у вас прошивка? У меня NodeMCU. Подключение занимает до 5 секунд, еще 1-2 — передача данных. В таком режиме повербанк на 1 шт 18650 заканчивается за 2 недели…
Barnaby
25.09.2017 07:48Прошивка — скетч для arduino ide. Скорее всего у вас включен DHCP-клиент, с ним было 0.8-2.5с подключение в зависимости от роутера, в ардуино это решается через WiFi.config(ip, gw, sn) сразу после старта. Еще esp запоминает настройки вайфая и сам подключается, инициализировать подключение каждый раз не нужно.
Передача очень долгая если сервер в локалке, мб сервер такой, у меня датчики сразу кидают данные через tcp и если нет команд в очереди сервер шлет '\n' и разрывает соединение.
Jeyko
23.09.2017 19:51+2Думал будет интересно… С интернета брать прогноз — это не метод.
hzs
24.09.2017 00:14Вполне себе метод, особенно если все окна выходят на юг и на солнце весь день градусник показывает +35… +45. Куда датчик не вешай, один фиг он будет нагреваться и врать до 25 градусов.
И берётся не прогноз, а текущая температура, погрешность, думаю, градусов 5 максимум будет.
Это если систему управления климатом дома делать, тут конечно по несколько датчиков в каждую комнату надо и одной ESP8266 на комнату будет в самый раз.
mike_y_k
24.09.2017 01:36Интересная идея.
А GRIB в качестве источника метеоданных не пробовали? Статистическая точность отображения у них повыше будет — таки не совсем для граждан данные.
А RPI для такого слишком избыточно, только если некоторой дополнительной нагрузкой на уже достаточно задействованное устройство.
Это все спокойно можно поднять и на ESP, а с появлением семейства камней ESP32 все стало ещё проще. Да и цена сильно разнится. В 32 не только WiFi c BT на борту, но и даже обычный LAN присутствует.
А с собственными датчиками даже на солнечной стороне можно разобраться. Минимум парой в двух трубах с разного цвета поверхностю и/или материалом и поправочной таблицей.DmitrySpb79 Автор
24.09.2017 17:47GRIB не пробовал, если это аналог raw-данных, то самому делать расчет — уже пожалуй черезчур получается.
На ESP32 пойдет разумеется, даже на обычной ESP наверно тоже, только web-запросы придется портировать на Micropython. Ну и у меня уже валяются и старая «малина» и дисплей от нее, так что кроме трудозатрат, все бесплатно.mike_y_k
25.09.2017 14:54Для GRIB есть описание запросов и данных, есть API, есть программы с открытым кодом ( например zgrib). В программах почти весь функционал — красивое отображение на экране ;).
На 8266 будет сильно геморройнее реализовать, разве что на lua… :(
Приставка micro не делает продукт отличимым от родителя ;). И под оригинальным (и любом другом) Python будет работать.
Валяется — это не совсем бесплатно. Тут просто опыт реализации, как компенсация затрат в прошлом.
Jmann
24.09.2017 07:44Сам поклонник малины, но приберёг ее для более серьёзных целей Я тоже решил для себя, что актуальней всего прогноз погоды за моим окном. И сделал девайсу на Atmega168.
DmitrySpb79 Автор
24.09.2017 17:51Да, сейчас ESP32 за 7$ — и дешево и сердито.
Но старая «малина» наверное у каждого есть, а для вывода погоды и RPi1 хватит.
ukt
24.09.2017 09:21А может кто поможет ссылкой на примеры драйверов для расбери?
Хочу драйвер из GPIO в SPI сделать, а знаний пока не хватает.DmitrySpb79 Автор
24.09.2017 17:53Вам возможно и не нужен драйвер, можно посылать данные по SPI прямо из приложения.
www.takaitra.com/posts/492
lingvo
24.09.2017 10:22У меня в качестве платформы стоит OpenHAB. Температуру беру из интернета, используя Weather Underground. Достаточно точно. Все данные отображаются на настенных планшетах.
По поводу локальной погоды — для управления автоматическим закрытием маркизы и мансардного окна мне нужны были датчики ветра и дождя. Они бывают готовые, их только надо подключить к соответствующим входным модулям. У меня сеть построена на Z-wave, поэтому использовал Fibaro Binary Sensor.
Mulin
24.09.2017 16:30+1Использовать цветной TFT дисплей, для того что бы эмулировать монохромный символьный :)
И все это на малинке.
buldo
24.09.2017 23:18У меня есть подобный дисплей. Выполнение пары скриптов позволяет использовать его не напрямую по spi, а как обычный дисплей, запускать иксы и всякие DE.
Вам не кажется, что написать полноэкранное Qt приложение проще и даже «более кроссплатформенно»?DmitrySpb79 Автор
24.09.2017 23:26Да, я экран в таком виде тоже использовал. Но для таких несложных задач консоль мне больше нравится.
mike_y_k
25.09.2017 14:59А полегче вариант реализации выбрать? xfce и на GTK. Собственно и без них вполне X достаточно. Это не система со сложными окнами. Вполне можно обойтись даже библиотеками Python для окон.
buldo
25.09.2017 15:05На самом деле для таких случаев можно использовать хитрый режим Qt, когда приложение вообще без Иксов запускается
DmitrySpb79 Автор
25.09.2017 15:19Кстати интересно, можно ли как-то активировать на Raspberry Pi графический режим без иксов, примерно как раньше во времена MSDOS было.
buldo
25.09.2017 15:31Если работает консоль, то не вижу причин, почему что-то другое не должно работать.
Хотя не уверен, что драйвер для этого дисплея поддерживает ускорение.
Примерmike_y_k
25.09.2017 16:54Так там FB таки запускается, а дальше уже на нем повторит путь X по выводу графической информации в необходимом объёме и функционале.
Собственно по ключу FB поиск ведёт к готовым вариантам использования.
apoluekt
25.09.2017 19:53+2Буквально вчера сделал похожую штуку на трехцветном e-ink дисплее WaveShare:
По-моему, e-ink для таких применений лучше приспособлен, погода каждую секунду не меняется, а смотреть приятнее. Правда, у трехцветного дисплея обнаружилась неприятная особенность: прорисовка занимает 15 секонд, в течение которых он моргает всеми своими тремя цветами, а частичной прорисовки нет (по крайней мере, на уровне библиотеки).
Прогноз и текущяя погода берется с Weather Underground API, он умеет выдавать почасовой детальный прогноз на 10 дней в json. Очень рекомендую.mike_y_k
26.09.2017 05:57На Waveshare для всех трехцветных в колонке partial update указано No. Возможно это уже аппаратная проблема контроллера.
Для исключения моргания там вроде как на время обновления можно подавить вывод на экран. Давно последний раз их пользовал, но эта проблема была как-то решена.apoluekt
26.09.2017 08:45+1Что-то не уверен я, что на e-ink можно подавить вывод во время обновления, просто исходя из самого принципа его работы.
mike_y_k
26.09.2017 15:11Надо поднимать DS и смотреть. Сейчас их нет под рукой для натурного эксперимента, а в коде для прошивки на ассемблере из-за цейтнота практически полностью отсутствуют комментарии. Ждёт нужного сочетания планет для причесывания кода перед помещением в архив.
RafaelRS
Не совсем уверен в целесообразности такой станции. Можно уж тогда виджет на рабочий стол или systray вывести
DmitrySpb79 Автор
Погодная станция нужна как раз для того, чтобы видеть погоду не подходя к компу :) Одеваюсь утром на работу например, удобно знать температуру.
hurtavy
Одеваясь утром хотелось бы знать температуру на улице, а не в интернете.
DmitrySpb79 Автор
Вопрос на самом деле интересный :) Прогнозы погоды бывает и врут, а текущая погода должна быть вполне точная, если конечно не жить в такой глухомани где до ближайшей метеостанции 100км. Я не думаю, что для городов погрешность будет большой.
hurtavy
Ну… У меня прогноз на телефоне и на компе. Прогнозы берутся с разных сайтов. Та же температура часто отличается на 3-5 градусов — вот вам и погрешность
I-denis
в телефон вы утром смотрите? виджет на главный экран с часами.
в варианте raspberry интересно железячное решение с точки зрения конструкции выходного дня, как вариант. датчики влажности, освещенности, температуры доступны на любой вкус, подключение по шинам i2c, spi — что вообще не требует шилда и позволяет вынести датчики на расстояние от коробки.
при более глубоком проникновении а тему можно внешний блок сделать беспроводным и оборудовать анемометром, датчиком количества осадков и тд. дисплеи с тачскрином есть 5-7-8" подключаемые в режиме параллельного интерфейса или spi. что может доставить удовольствие в плане программирования этой связки
I-denis
и опять же, если вы хотите шилд с датчиками относящимися к категории метео — вам подойдёт плата расширения для прототипирования — с разведённым разъемом и кучей монтажный отверстий. на ней вы можете собрать связку из барометра, гигрометра, датчика температуры и тд за пару часов
DmitrySpb79 Автор
Да, код написан так что добавить новый источник данных можно, не затрагивая UI и остальные классы. Но пока большого смысла не вижу, точности онлайн-прогноза по ощущениям, вполне хватает, ну а интернет дома всегда есть.
DmitrySpb79 Автор
Насчет платы расширения понятно, вопрос был о покупке готового шилда, с уже установленным экраном, датчиками и разъемами.
DmitrySpb79 Автор
Кстати про i2c, spi, опять же повторюсь, хороших шилдов готовых в продаже нет. Например тот же шилд с TFT от adafruit — ни один разъем не выведен, ставишь шилд, вся плата закрывается наглухо. Обратная сторона ведь пустая, что мешало хотя бы i2c вывести. Странные люди их проектировали, или же цель была сэкономить каждый цент.
Bluewolf
Покупаем смартфон\планшет (стоимость 2-10 т.р. в зависимости от желаемого качества экрана), вешаем на стену, подключаем к заряднику. На экран выводим желаемое готовым или самописным приложением. Профит! При желании планшет\смартфон можно вклеить в настольную или настенную рамку. Бонусы — встроенный корпус, встроенный аккумулятор, встроенный GSM-канал,…
Если хочется поработать с электроникой, делаем датчик местной погоды с BT-каналом.
DmitrySpb79 Автор
Я как-то думал о таком варианте, остановила мысль о надежности аккума и зарядки в режиме постоянного включения — все-таки это не штатный режим для телефона.
lingvo
У меня уже 1,5 года висят три планшета за 60 баксов в режиме постоянной зарядки и постоянно включенного дисплея. Пока полет нормальный.
Ni2c2k
Можно использовать суточный таймер для подачи напряжения для зарядки на несколько часов в сутки.
DmitrySpb79 Автор
Проще вообще батарею вытащить, если она конечно съемная.