Русский
Русский
English
Статистика
Реклама

Погода

Собираем недорогой 9.7quot E-Ink дисплей для отображения чего угодно

08.07.2020 12:13:32 | Автор: admin
Всем привет. Давно хотел собрать большой E-Ink дисплей, который можно поставить на стол и отображать на нем полезную информацию (погоду, календарь и т.д.) В этой статье расскажу, как можно собрать такое устройство на базе ESP32 и дисплея от Kindle DX значительно дешевле, чем Waveshare.



Идея собрать такое устройство возникла еще зимой. Отдавать 120 вечнозеленых за дисплей от Waveshare и 30 за их контроллер совсем не хотелось. Поиск на али показал, что можно купить 9.7 дисплей ED097OC4 от Kindle DX за 30 долларов с доставкой. На нем и решил остановиться.
После гугления решил остановиться на вот этом самодельном контроллере hackaday.io/project/168193-epdiy-976-e-paper-controller и он же на гитхабе github.com/vroland/epdiy Проект активно развивается и я решил к нему присоединиться.

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



Связался с автором проекта, пришли к выводу, что причиной мог стать сдвиговый регистр (я применил немного не тот, который указан). Но предположение не подтвердилось. После ковыряния кода и экспериментов с частотой сигнала было найдено решение.
Как оказалось, дисплеи ED097OC4 бывают как минимум трех типов: обычный ED097OC4, высоко контрастный ED097TC2 (если хотите такой, стоит уточнить у продавца) и низкого качестве, которые и попались мне. Подробности изучения проблемы доступны вот здесь github.com/vroland/epdiy/issues/15

Тем не менее, фикс в прошивке сделан и все заработало с почти незаметными артефактами в виде сжатия нескольких пикселей в районе полос на 1/3 и 2/3 экрана (обратите внимание на показания температуры на первой картинке в статье).

Пришло время написать программу для отображения погоды. Тут пришлось допилить драйвер и добавить недостающие функции отрисовки. А дальше портируем вот этот замечательный проект github.com/G6EJD/ESP32-e-Paper-Weather-Display под наш дисплей и драйвер, немного меняем расположения элементов, убираем рамки и делаем прочие украшательства на свой вкус. Подробно останавливаться на коде не буду, все описал на гитхабе github.com/vroland/epdiy/tree/master/examples/weather

В итоге имеем интересное многофункциональное устройство на базе уже народного модуля умного дома ESP32 и одного из самых больших и доступных E-Ink дисплеев на рынке. Все вместе (дисплей, компоненты, печатные платы) мне обошлось около 70 долларов.

Полезные ссылки:
essentialscrap.com/eink/waveforms.html
hackaday.io/project/21607-paperback-a-desktop-epaper-monitor
hackaday.io/project/11537-nekocal-an-e-ink-calendar
Подробнее..

Метеостанция на максималках

05.03.2021 10:06:07 | Автор: admin

Про метеостанцию на Хабре писали не раз и не два, и наверное не с десяток раз. И вот настало моё время. Решил с вами поделиться своей.

Постановка задачи

Зачем вообще нужна метеостанция? Сегодня в мире хватает погодных сервисов, в том числе с локальными сводками погоды. Однако помимо контроля внешних параметров мне нужно было получить данные и с датчиков температуры и влажности внутри помещения. Помимо просто информационной составляющей, зная температуру в доме и снаружи, можно, например, управлять котлом или вентиляцией, и поддерживать комфортный микроклимат (погодозависимая автоматика). Кроме того, мне очень хотелось бы отслеживать тенденции и тренды погоды на длительных промежутках времени, например в год-два. То есть, данные нужно где-то хранить.

Из всего того делаем выводы:

  • Нужно хранилище данных (сервер)

  • Датчики будем использовать разные и в разных местах, поэтому проще сделать систему модульной (IoT)

  • Помимо локального сервера данные, хотя бы текущих показаний хорошо бы скидывать в облако

  • Так как мы будем собирать достаточно много данных, можно данными поделиться

Архитектура

Самым простым и популярным решением для метеостанции является Arduino, однако подружить с его домашней сетью - это дополнительные девайсы\шилды, лишние деньги и сложность, а значит - время. Поэтому из коробки проще использовать модуль уже со встроенным Wi-Fi, например ESP8266 (NodeMCU) с подключенными сенсорами. Это достаточно удобно, что один и тот же модуль можно использовать и дома, и за окном. При желании даже можно его использовать в качестве сервера.

Но почему бы не проставить в центр системы лучше что-то помощнее? Благо у меня пылится без дела Raspberry Pi первой ревизии (но и любая другая подойдёт). Внутренние датчики можно подключить, в принципе через GPIO и к малинке напрямую, но у меня роутер с малинкой в одной комнате установлен, а мониторить нужно другую. Если у вас такой проблемы нет - то можно от одной NodeMCU избавиться. Малинка будет получать данные от датчиков, сохранять их в базе данных и при необходимости отображать. Так же к GPIO Raspberry Pi можно подцепить LoRa - приёмник и получать данные от удалённых за пределами Wi-Fi сети датчиков (и вот они Arduino). Ну, и наконец, малинка будет отправлять данные в облако.

Итого, нам понадобится:

  • Raspberry PI

  • ESP8266 (2шт. + 1шт. опционально)

  • BME280 (2 шт.)

  • Часы реального времени DS1302 (опционально)

  • OLED-дисплей 128х64 на SH1106 (опционально)

  • Датчик дождя на компараторе LM373 (опционально)

  • УФ-датчик GY-VEML6070 (опционально)

  • Raspberry Pi Camera (опционально)

  • Arduino Nano (2 шт., опционально)

  • SX1278 (3 шт., опционально)

  • Магнитный компас с чипом QMC5883L/HMC5883L (опционально)

  • Датчик освещённости (светодиодный) с компаратором LM737 (опционально)

  • Датчики напряжения до 25V (опционально)

  • Датчики тока ACS712 (опционально)

Подключение SX1278 к Raspberry Pi

Для начала подключим к малинке радиомодуль.

Raspberry Pi

SX1278

3.3V

3.3V

GROUND

GROUND

GPIO10

MOSI

GPIO9

MISO

GPIO11

SCK

GPIO8

NSS/ENABLE

GPIO4

DIO0

GPIO22

RST

Соединяем пины Raspberry Pi и SX1278 как на картинке:

Замечание: для разных ревизий Raspberry Pi используются разное количество пинов, а значит и распиновки, смотрите документацию.

По поводу использования LoRa-модулей хочу обратить внимание на несколько моментов:

  • Перед подачей питания на модуль LoRa обязательно убедитесь, что к нему подключена антенна, иначе есть риск, что модуль сгорит!

  • На качество сигнала помимо антенны влияют правильные настройки, весьма важно, чтобы частоты приёмника и передатчика совпадали, а диапазон был свободен от шума (например игрушечных радиоуправляемых машинок)

Установка сервера

На Raspberry Pi загружаем Raspberry Pi OS Lite.

Далее устанавливаем статический адрес для нашей малинки:

sudo nano /etc/dhcpcd.conf

Добавляем\правим строки на наш желаемый IP и IP наш роутер

interfaceeth0# или wlan0 если малинка подключена по Wi-Fistaticip_address=192.168.0.4/24staticrouters=192.168.0.1staticdomain_name_servers=192.168.0.1. 8.8.8.8

Теперь включаем удалённый доступ через SSH, SPI (нужен для подключения LoRa), а так же Camera, если планируем её использовать.

sudo raspi-config

Включаем:

  • SSH (если собираемся подключаться по SSH, а не только через клавиатуру)

  • SPI (если собираемся использовать LoRa)

  • Camera (если собираемся использовать камеру)

Убеждаемся, что стоит автологин при загрузке:

Boot Options -> Console Autologin

Выходим из raspi-config, перезагружаем:

sudo shutdown -r now

Теперь у нас есть удалённый доступ к малинке, можем подключиться через ssh или можем продолжить через клавиатуру.

Вся логика сервера написана на Python3, поэтому ставим его:

sudo apt-get install python3.7

Теперь осталось загрузить собственно мой проект H.O.M.E.:

cd ~git clone https://github.com/wwakabobik/home.git

В качестве веб-сервера я выбрал flask, на Хабре есть отличная серия статей, поэтому я не буду останавливаться на подробностях при работе с ним.

Копируем контент из папки с сервером:

mkdir web-servercp -r home/home_server/* /home/pi/web-server/

Устанавливаем все зависимости:

cd web-serversudo python3.7 -m pip install-rrequirements.txt

Создаём базу данных из шаблона:

cat db/schema.sql | sqlite3 flask_db

Собственно всё, теперь можем запустить сервер:

cd /home/pi/web-server && sudo python3.7 app.py

Но мы же хотим, чтобы сервер запускался при загрузке Raspberry Pi?

Тогда в конце /etc/rc.local, перед exit 0, добавляем вызов bash-скрипта:

/home/pi/flask_startup.sh &

Копируем этот скрипт на место:

cd ~cp ~/home/bash/flask_startup.sh .

Я так же считаю, что было бы неплохо иметь скрипт, который проверяет, жив ли ещё сервер, и если он мёртв, то перезапускает его. Копируем и его.

cp ~/home/bash/check_health.sh .

Добавляем в планировщик cron:

sudo crontab -e

задание:

1-59/5 * * * * /home/pi/check_health.sh

Немного о софте сервера

За запуск сервера отвечает app.py.

#!/usr/bin/env python3.7from multiprocessing.pool import ThreadPoolfrom flask import Flaskfrom db.db import init_appfrom lora_receiver import run_loraapp = Flask(__name__, template_folder='templates')  # firstly, start Flask# import all routesimport routes.apiimport routes.pagesimport routes.single_pageif __name__ == '__main__':    # Start LoRa receiver as subprocess    pool = ThreadPool(processes=1)    pool.apply_async(run_lora)    # Start Flask server    init_app(app)    app.run(debug=True, host='0.0.0.0', port='80')    # Teardown    pool.terminate()    pool.join()

Обратите внимание, что помимо запуска сервера, в отдельном процессе запускаем LoRa ресивер, который будет получать данные от датчиков и пересылать их на сервер.

В остальном архитектура типична для flaska: все возможные routes вынесены в отдельные файлы, все страницы хранятся в pages, а шаблоны в templates. Логика базы данных лежит в db, статичные файлы (картинки) в static, ну а в camera будем складывать картинки с камеры.

В итоге, текущие показания можно увидеть на dashboard страницах,

а графики и данные - на отдельных (графики рисует plotly).

Софт LoRa-ресивера

home_server/lora_receiver.py

from time import sleepimport requestsfrom SX127x.LoRa import *from SX127x.board_config import BOARDendpoint = "http://0.0.0.0:80/api/v1"class LoRaRcvCont(LoRa):    def __init__(self, verbose=False):        super(LoRaRcvCont, self).__init__(verbose)        self.set_mode(MODE.SLEEP)        self.set_dio_mapping([0] * 6)    def start(self):        self.reset_ptr_rx()        self.set_mode(MODE.RXCONT)        while True:            sleep(.5)            rssi_value = self.get_rssi_value()            status = self.get_modem_status()            sys.stdout.flush()    def on_rx_done(self):        self.clear_irq_flags(RxDone=1)        payload = self.read_payload(nocheck=True)        formatted_payload = bytes(payload).decode("utf-8", 'ignore')        status = self.send_to_home(formatted_payload)        if status:            sleep(1)  # we got the data, force sleep for a while to skip repeats        self.set_mode(MODE.SLEEP)        self.reset_ptr_rx()        self.set_mode(MODE.RXCONT)    def send_to_home(self, payload):        if str(payload[:2]) == '0,':            requests.post(url=f'{endpoint}/add_wind_data', json={'data': payload})        elif str(payload[:2]) == '1,':            requests.post(url=f'{endpoint}/add_power_data', json={'data': payload})        else:            print("Garbage collected, ignoring")  # debug            status = 1        return statusdef run_lora():    BOARD.setup()    lora = LoRaRcvCont(verbose=False)    lora.set_mode(MODE.STDBY)    # Medium Range  Defaults after init are 434.0MHz, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 13 dBm    lora.set_pa_config(pa_select=1)    assert (lora.get_agc_auto_on() == 1)    try:        lora.start()    finally:        lora.set_mode(MODE.SLEEP)        BOARD.teardown()

В этом коде главное - это получение пакета в событии on_rx_done - если пакет получен, нужно его декодировать.

Проверяем в send_to_home что payload[:2] равен ожидаемому коду датчика (я для простоты использую значения 0, и 1,), то отсылаем на сервер и спим секунду, чтобы пропустить повторные пакеты.Если нет, продолжаем получать пакеты.

API


Ключевое, что делает 99% времени сервер - это простой. Но в остальные 1% он отдаёт и получает данные, и за это, помимо отображения страниц через веб-интерфейс отвечает API.

Именно через Flask REST API мы будем посылать или получать данные от сенсоров.

home_server/routes/api.py

@app.route('/api/v1/send_data')def send_weather_data():    return send_data()@app.route('/api/v1/add_weather_data', methods=['POST'])def store_weather_data():    if not request.json:        abort(400)    timestamp = str(datetime.now())    unix_timestamp = int(time())    data = request.json.get('data', "")    db_data = f'"{timestamp}", {unix_timestamp}, {data}'    store_weather_data(db_data)    return jsonify({'data': db_data}), 201

Данные пишутся в лог:

В моём случае, если мы получили данные от датчика (получили POST запрос с верным JSON), то мы их сохраняем в БД. Так же, если мы получили GET запрос на отправку данных (send_data), то данные отправляем данные на облако.

home_server/pages/weather_station/send_data.py

def send_data():    data = get_last_measurement_pack('0', '1')    image = take_photo()    wu_data = prepare_wu_format(data=data)    response = str(send_data_to_wu(wu_data))    response += str(send_data_to_pwsw(wu_data))    response += str(send_data_to_ow(data))    response += str(send_data_to_nardmon(data))    send_image_to_wu(image)    copyfile(image, f'{getcwd()}/camera/image.jpg')    return response

Ах да, забыл упомянуть камеру. Если мы подключили камеру к Raspberry Pi, то можем отправлять или сохранять изображения погоды за окном. Для этого есть отдельный метод:

home_server/pages/shared/tools.py

from picamera import PiCamera<...>camera = PiCamera()<...>def take_photo():  camera.resolution = (1280, 720) # lower resolution to fit in limits  camera.start_preview()  sleep(5)  image = f'{getcwd()}/camera/image_{int(time())}.jpg'  camera.capture(image)  camera.stop_preview()  return image  

Внешние датчики

полные скетчи можно найти в home/iot

Самым удобным и простым модулем для любительской метеостанции является модуль BME280, объединяющий в себе термометр, датчик влажности и давления. Подключаем его по I2C к ESP8266:

Прошивать будем через Arduino IDE (как добавить ESP8266 написано, например, в этой статье).

iot/esp8266/weatherstation_in/weatherstation_in.ino

#include <ESP8266WiFi.h>#include <ESP8266HTTPClient.h>#include <Wire.h>#include <SPI.h>#include <Adafruit_BME280.h>#include <Arduino_JSON.h>Adafruit_BME280 bme; // use I2C interfaceAdafruit_Sensor *bme_temp = bme.getTemperatureSensor();Adafruit_Sensor *bme_pressure = bme.getPressureSensor();Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();// Датчик не сказать, чтобы очень точный, поэтому добавляем корректирующие значенияfloat correction_temperature = -0.5;float correction_pressure = 15;float correction_humidity = 10;// подключаем Wifivoid connect_to_WiFi(){ WiFi.mode(WIFI_STA); WiFi.begin(wifi_ssid, wifi_password); while (WiFi.status() != WL_CONNECTED) {   delay(500); } Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); #endif}/* <> */// собираем данные с датчиковfloat get_temperature(){  sensors_event_t temp_event, pressure_event, humidity_event;  bme_temp->getEvent(&temp_event);  return temp_event.temperature + correction_temperature;}/* <> */// также точку росы можно вычислить до отправки на сервер, делаем это:float get_dew_point(){  float dew_point;  float temp = get_temperature();  float humi = get_humidity();  dew_point = (temp - (14.55 + 0.114 * temp) * (1 - (0.01 * humi)) - pow(((2.5 + 0.007 * temp) * (1 - (0.01 * humi))),3) - (15.9 + 0.117 * temp) * pow((1 - (0.01 * humi)), 14));  return dew_point;}/* <> */// Форматируем в строкуString get_csv_data(){  String ret_string = DEVICE_ID;  ret_string += delimiter + String(get_temperature());  ret_string += delimiter + String(get_humidity());  ret_string += delimiter + String(get_pressure());  ret_string += delimiter + String(get_dew_point());  return ret_string;}// Отправляем через HTTP, упаковав строку в JSON:void post_data(){  check_connection();  HTTPClient http;  //Declare object of class HTTPClient  String content = get_csv_data();  int http_code = 404;  int retries = 0;  while (http_code != 201)  {    http.begin(api_url); // connect to request destination    http.addHeader("Content-Type", "application/json");    // set content-type header    http_code = http.POST("{\"data\": \"" + content +"\"}");  // send the request    http.end();                        // close connection    retries++;    if (retries > max_retries)    {          Serial.println("Package lost!");      break;    }  }}// cобственно, повторяем это время от времени:void loop(){  post_data();  delay(cooldown);}

По умолчанию у меня стоит интервал в 5 минут, и я считаю, что DEVICE_ID = "0" внутренний датчик, а DEVICE_ID = "1" внешний.

Датчик дождя LM393+YL83Датчик дождя LM393+YL83

К внешнему датчику можно подключить так же датчики ультрафиолета (
GY-VEML6070) и датчик дождя (на компараторе LM393). YL-83 достаточно игрушечный вариант для реального измерения уровня осадков, по крайней мере без калибровки, но, на какое-то время сгодиться, потому что мне актуальность по уровню осадкам не сильно интересует. Ну, точнее интересует на уровне "на улице дождь" или "сухо". Так же, альтернативно, можно использовать аналоговый датчик ультрафиолета GY-8511, но тогда придётся выбирать между ним и датчиком дождя, так как аналоговый вход на NodeMCU только один. Датчик ультрафиолета можно использовать, например, для оценки эффективности солнечных панелей. Ну и просто показывает дни, когда лучше воспользоваться солнцезащитным кремом во время покоса газона.

Схема подключения к ESP8266 ниже:

Для этих датчиков соответственно добавим три функции:

iot/esp8266/weatherstation_out/weatherstation_out.ino

#include "Adafruit_VEML6070.h"Adafruit_VEML6070 uv = Adafruit_VEML6070();#define VEML6070_ADDR_L   (0x38) ///< Low addressRAIN_SENSOR_PIN = A0;/* <...> */#ifdef UV_ANALOG_SENSORvoid get_uv_level(){    int uv_level = averageAnalogRead(UV_PIN);    float uv_intensity = mapfloat(uv_level, 0.99, 2.8, 0.0, 15.0);    return uv_intensity;}#endif#ifdef UV_I2C_SENSORvoid get_uv_level(){return uv.readUV();}#endif#ifdef RAIN_SENSORvoid get_rain_level(){    int rain_level = averageAnalogRead(RAIN_SENSOR_PIN);    return rain_level;}#endif

NodeMCU удобно использовать, когда есть устойчивый Wi-Fi в зоне их действия. Конечно, ставить внешние датчики для погодной станции на крыльце - плохая идея, но оборудованная точка, отнесённая пару-тройку метров от дома - то, что нужно, а сигнала роутера в доме хватает за глаза.

Правила установки погодной станции
  • Датчики температуры и влажности воздуха обязательно устанавливаются над естественной поверхностью земли (трава, грунт). Асфальта, бетона, щебня, камня, металла не должно быть.

  • Датчики температуры и влажности устанавливаются на высоте 2 м над землёй в метеорологической будке: это небольшой деревянный или пластиковый ящик (размером приблизительно 40х40х40 см) с белыми, отражающими свет перфорированными или жалюзийными стенками, а также солнцеводозащитным козырьком (крышка будки должна быть герметичной и иметь наклон для стекания осадков с будки).

  • Датчик ветра - на высоте 10-12 м над землёй (именно над землёй, а не на крышах зданий; в исключительном случае разрешается размещение дачтика ветра на крыше одноэтажного дома, так чтобы датчик возвышался над верхним краем крыши не менее чем на 2-3 м, а над поверхностью земли на 10-12 м).

  • В худшем случае (при этом велик риск погрешностей, особенно в ночное время) датчик Т и влажности может быть установлен с теневой стороны здания, на высоте 2 м над землёй, на штанге длиной от стены как минимум метра 3 , над газоном (не над асфальтом!). Ни в коем случае не рекомендуется устанавливать их поблизости от сильно нагревающихся поверхностей, например крыш, стен и т.п.

  • Датчик атмосферного давления устанавливается в помещении вдали от окон и отопительных приборов. Атмосферное давление зависит от высоты над уровнем моря места, где производится измерение; поэтому требуется калибровка датчика давления перед его использованием. Для правильной установки прибора необходимо воспользоваться показаниями другого барометра или данными ближайшей метеостанции (с учётом разности высот, определённой по подробной топографической карте; 10 м подъёма соответствует уменьшению давления примерно на 1 мм рт.ст. или 1.3 гПа (мБ)).

Как опция, можем добавить ещё одно устройство на ESP8266, которое будет отображать данные с метеостанции. В моём случае - удобно не просто подключить дисплей к внутреннему датчику, а иметь независимое устройство, которое можно расположить где угодно. Для того, чтобы оно что-нибудь ещё делало - добавим к нему часы реального времени.

Затем загрузим на него скетч, который будет отображать текущее время (ЧЧ:ММ) и в бегущей строке данные с метеостанции:

iot/informer/esp8266/informer/informer.ino

#include <ESP8266WiFi.h>#include <ESP8266HTTPClient.h>#include <Wire.h>#include <U8g2lib.h>#include <virtuabotixRTC.h>  // https://ampermarket.kz/files/rtc_virtualbotix.zip// RTCvirtuabotixRTC myRTC(14, 12, 13);// OLEDU8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);u8g2_uint_t offset;            // current offset for the scrolling textu8g2_uint_t width;             // pixel width of the scrolling text (must be lesser than 128 unless U8G2_16BIT is definedconst int string_length = 80;  // maximum count of symbols in marqueechar text[string_length];      // text buffer to scroll// Wi-Ficonst char* wifi_ssid = "YOUR_SSID";const char* wifi_password = "YOUR_PASSWORD";// APIconst String ip_address = "YOUR_IP_OF_SERVER";const String port = "YOUR_PORT";const String api_endpoint = "/api/v1/add_weather_data";const String api_url = "http://" + ip_address + ":" + port + api_endpoint;const int max_retries = 5;  // number of retries to send packet// Timers and delaysconst long data_retrieve_delay = 300000;const int cycle_delay = 5;unsigned long last_measurement = 0;void setup(void) {    Serial.begin(9600);    init_OLED();    init_RTC();}/* Init functions */void init_OLED(){    u8g2.begin();      u8g2.setFont(u8g2_font_inb30_mr); // set the target font to calculate the pixel width    u8g2.setFontMode(0);              // enable transparent mode, which is faster}void init_RTC(){    // seconds, minutes, hours, day of the week, day of the month, month, year    // раскомментируйте при прошивке, заполнив текущую дату и время, затем снова закомментируйте и прошейте ещё раз    //myRTC.setDS1302Time(30, 03, 22, 5, 19, 2, 2021); // set RTC time    myRTC.updateTime(); // update of variables for time or accessing the individual elements.}""" <...> """  String get_data(){    check_connection();    #ifdef DEBUG    Serial.println("Obtaining data from server");    #endif    HTTPClient http;    //Declare object of class HTTPClient      int http_code = 404;    int retries = 0;    String payload = "Data retrieve error";    while (http_code != 200)    {        http.begin(api_url);                // connect to request destination        http_code = http.GET();             // send the request        String answer = http.getString();   // get response payload        http.end();                         // close connection            retries++;        if (retries > max_retries)        {            break;            #ifdef DEBUG            Serial.println("Couldn't get the data!");            #endif        }                        if (http_code == 200)        {            payload = answer;        }    }    return payload;}void loop(void) {    // Check that new data is needed to be retrieved from server    if (((millis() - last_measurement) > data_retrieve_delay) or last_measurement == 0)    {        String stext = get_data();        stext.toCharArray(text, string_length);        last_measurement = millis();        width = u8g2.getUTF8Width(text);    // calculate the pixel width of the text        offset = 0;    }    // Update RTC    myRTC.updateTime();     // Now update OLED    u8g2_uint_t x;    u8g2.firstPage();    do     {        // draw the scrolling text at current offset        x = offset;        u8g2.setFont(u8g2_font_inb16_mr);       // set the target font        do         {                                       // repeated drawing of the scrolling text...            u8g2.drawUTF8(x, 58, text);         // draw the scrolling text            x += width;                         // add the pixel width of the scrolling text        } while (x < u8g2.getDisplayWidth());   // draw again until the complete display is filled            u8g2.setFont(u8g2_font_inb30_mr);       // choose big font for clock        u8g2.setCursor(0, 30);                  // set position of clock        char buf[8];                            // init bufer to formatted string        sprintf_P(buf, PSTR("%02d:%02d"), myRTC.hours, myRTC.minutes); // format clock with leading zeros        u8g2.print(buf);                        // display clock    } while (u8g2.nextPage());      offset-=2;                       // scroll by two pixels    if ((u8g2_uint_t)offset < ((u8g2_uint_t) - width))    {          offset = 0;                  // start over again    }      delay(cycle_delay);              // do some small delay}

В итоге результат работы выглядит так:

Соответственно в Raspberry Pi:

home_server/routes/api.py

@app.route('/api/v1/get_weather_data', methods=['GET'])def store_wind_data():    return send_data_to_informer()  

pages/weather_station/send.data

def send_data_to_informer():    data_in = get_last_measurement_pack('weather_data', '0', '0')    data_out = get_last_measurement_pack('weather_data', '0', '1')    pressure = int((data_in['pressure']+data_out['pressure'])/2)    formatted_string = f"IN: T={data_in['temperature']}*C, " \                       f"H={data_in['humidity']}% | " \                       f"OUT: T={data_out['temperature']}*C, " \                       f"H={data_out['humidity']}%, " \                       f"DP={data_out['dew_point']}*C | " \                       f"P={pressure} mmhg"    return formatted_string

Радиодатчики

Там, где не дотянуться Wi-Fi, нужно использовать альтернативные варианты передачи данных. В моём случае - это использование LoRa-модулей (в связке, например, с Arduino Nano.

Таких устройств у меня два - это датчик скорости и направления ветра (компас). Пока не буду останавливаться на этом в текущей статье, если будет интерес - напишу отдельно. Второе устройство - это вольтметр и два амперметра, для контроля работы ветряка, зарядки АКБ и потребления.

SX1278

Arduino Nano

3.3V

3.3V

GROUND

GROUND

MOSI

D10

MISO

D2

SCK

D13

NSS/ENABLE

D12

DIO0

D11

RST

D9

И, код, соответственно:

iot/arduino/*_meter/*_meter.ino

// Required includes#include <SPI.h>#include <LoRa.h>// LoRA configconst int LORA_SEND_RETRIES = 5; // сколько раз посылать сообщениеconst int LORA_SEND_DELAY = 20;  // задержка между пакетамиconst int LORA_POWER = 20;       // мощность передатчика на максимум const int LORA_RETRIES = 12;     // сколько раз пытаться инициализировать модульconst int LORA_DELAY = 500;      // задержка между попыткой инициализации// Инициализируем модульvoid init_LoRa() {    bool success = false;    for (int i=0; i < LORA_RETRIES; i++)        {        if (LoRa.begin(433E6)) // используем 433Мгц        {            success = true;            break;        }        delay(LORA_DELAY);    }    if (!success)    {        #ifdef DEBUG        Serial.println("LoRa init failed.");        #endif        stop(4);    }        LoRa.setTxPower(LORA_POWER);  // aplify TX power    #ifdef DEBUG    Serial.println("LoRa started!");    #endif  }#endif// Посылаем пакет с данными строкойvoid LoRa_send(power_data data){    String packet = DEVICE_ID + "," + String(data.avg_voltage,2) + ",";    packet += String(data.avg_current,2) + "," + String(data.avg_power,2) + "," +String(data.avg_consumption,2);    for (int i=0; i < LORA_SEND_RETRIES; i++)    {        LoRa.beginPacket();  // just open packet        LoRa.print(packet);  // send whole data        LoRa.endPacket();    // end packet        delay(LORA_SEND_DELAY);    }  }

Достаточно просто, не правда ли?

Облачные сервисы

Изначально у меня не было цели делиться данными со сторонними сервисами, но во время отладки появилась мысль о том, что неплохо было бы иметь референсные данные с местных метеостанций, для контроля корректности работы своей. Первым, и с самой большой коллекцией примеров и API оказалась WeatherUnderground.

from wunderground_pws import WUndergroundAPI, unitsfrom secure_data import wu_api_key, wu_reference_station_id""" ... """wu_current = wu.current()""" ... """wu_humidity=wu_current['observations'][0]['humidity'],wu_pressure=int(int(wu_current['observations'][0]['metric_si']['pressure'])/1.33),wu_dew_point=wu_current['observations'][0]['metric_si']['dewpt'],wu_wind_speed=wu_current['observations'][0]['metric_si']['windSpeed'],wu_wind_gust=wu_current['observations'][0]['metric_si']['windGust'],wu_wind_direction=wu_current['observations'][0]['winddir'],wu_wind_heading=deg_to_heading(int(wu_current['observations'][0]['winddir']))

Однако, если была возможность быстро получать данные, то почему бы ими не поделиться, подумал я? Данные в WU передаются через GET-запрос, поэтому для удобства предварительно подготавливаем данные

def prepare_wu_format(data, timestamp=None):    payload = f"&dateutc={timestamp}" if timestamp else "&dateutc=now"    payload += "&action=updateraw"    payload += "&humidity=" + "{0:.2f}".format(data['humidity'])    payload += "&tempf=" + str(celsius_to_fahrenheit(data['temperature']))    payload += "&baromin=" + str(mmhg_to_baromin(data['pressure']))    payload += "&dewptf=" + str(celsius_to_fahrenheit(data['dew_point']))    payload += "&heatindex=" + str(celsius_to_fahrenheit(heat_index(temp=data['temperature'], hum=data['humidity'])))    payload += "&humidex=" + str(celsius_to_fahrenheit(humidex(t=data['temperature'], d=data['dew_point'])))    payload += "&precip=" + str(data['precip'])    payload += "&uv" + str(data['uv'])    return payload

затем отправляем:

import requests""" ... """def send_data_to_wu(data):    wu_url = "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?"    wu_creds = "ID=" + wu_station_id + "&PASSWORD=" + wu_station_pwd    response = requests.get(f'{wu_url}{wu_creds}{data}')    return response.content

В результате мы должны увидеть данные на своей метеостанции.

Тут нужно сделать ремарку, что все сервисы, включая WU требуют регистрации и часто получения API ключей. Вся конфиденциальная информация хранится в secure_data.py

# Geo Datalatitude =longitude =altitude =cur_location =# WEATHER UNDERGROUND DATAwu_api_key =wu_station_id =wu_station_pwd =wu_reference_station_id =# OPEN WEATHER DATAow_api_key =ow_station_id =# PWSWEATHER DATApwsw_station_id =pwsw_api_key =# NARODMON DATAnarodmon_name = narodmon_owner = narodmon_mac = narodmon_api_key = 

Заполняем значения и продолжаем :)

WeatherUnderground увы, работает на платной основе и полученный мной ключ действует всего лишь год. Поэтому, поискав альтернативы, я наткнулся на PWS Weather.

Несмотря на то, что на сайте нет описания публичного API для сторонних устройств (не промышленных метеостанций), разработчики охотно по запросу присылают примеры, впрочем, за одну ночь и без их помощи решил задачу по отправке данных, благо формат данных сайт использует такой же, как и WU.

def send_data_to_pwsw(data):    pwsw_url = "http://www.pwsweather.com/pwsupdate/pwsupdate.php?"    pwsw_creds = "ID=" + pwsw_station_id + "&PASSWORD=" + pwsw_api_key    response = requests.get(f'{pwsw_url}{pwsw_creds}{data}')    return response.content

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

Ещё можно послать данные на OpenWeatherMap. Персональной страницы тут нет, а в ответ на исторические данные мы получим "средние" по больнице данные, но, почему бы и нет? Энтузиастам надо помогать. Для передачи показаний у OWM для PWS (personal weather station) своё API, но что-то я не нашёл готовой обёртки для него на python, поэтому написал свою.

В отличие американских WeatherUnderground и PWS Weather, использующих имперскую систему, разраработчики OpenWeatherMap из Латвии и используют метрическую систему (Си), поэтому для передачи показаний для них не используем конвертеры, а пишем данные сразу из базы данных, которые мы собрали с датчиков.

from openweather_pws import Stationdef send_data_to_ow(data):    pws = Station(api_key=ow_api_key, station_id=ow_station_id)    response = pws.measurements.set(temperature=data['temperature'], humidity=data['humidity'],                                    dew_point=data['dew_point'], pressure=data['pressure'],                                    heat_index=fahrenheit_to_celsius(heat_index(temp=data['temperature'],                                                                                hum=data['humidity'])),                                    humidex=humidex(t=data['temperature'], d=data['dew_point']))    return response

И, наконец, как вариант импортозамещения самый функциональный, позволяющий хранить в том числе данные с закрытых датчиков (например те же данные о температуре внутри дома) - Narodmon.

На сервисе достаточно богатое API, позволяющее не только передавать показания с датчиков, но и собирать информацию по геолокации, управлять самим устройством удалённо, так и социальные фишки вроде "поставить лайк" или отправить сообщение. Особо здорово, что сервис шлёт email'ы в случае проблем (например датчик не вышел на связь час), так и настраиваемые "проблемы" вроде превышения лимита на конкретном датчике. Но, как и в случае OWM я не нашёл полного API-wrapper для python, и опять написал свой. Теперь, чтобы отправить данные с датчиков, зовём:

def send_data_to_nardmon(data):    nm = Narodmon(mac=narodmon_mac, name=narodmon_name, owner=narodmon_owner,                  lat=latitude, lon=longitude, alt=altitude)    temperature = nm.via_json.prepare_sensor_data(id_in="TEMPC", value=data['temperature'])    pressure = nm.via_json.prepare_sensor_data(id_in="MMHG", value=(data['pressure']))    humidity = nm.via_json.prepare_sensor_data(id_in="HUM", value=data['humidity'])    dew_point = nm.via_json.prepare_sensor_data(id_in="DEW", value=data['dew_point'])    sensors = [temperature, pressure, humidity, dew_point]    response = nm.via_json.send_short_data(sensors=sensors)    return response

У данного сервиса есть одна дурацкая отличительная особенность, состоящая в том, что нельзя отправлять данные чаще чем раз в пять минут. Но на практике то ли у нас разные пять минут, то ли сайт подвисает, реально данные отправляются раз в 10-15 минут. Если всё сделано правильно, то увидим данные на сайте.

Немаловажным будет сказать, что для отправки данных следует "дёргать" ручку /api/v1/send_data пустым GET-запросом. Чтобы не изобретать велосипед, просто поручим это делать cron. Добавляем ещё одну строку:

*/5 * * * * /usr/bin/wget -O - -q -t 1 http://0.0.0.0:80/api/v1/send_data

А как же камера?

Пока никак. Сделанные фото можно передавать на WeatherUnderground. Это сделать несложно через ftp

from ftplib import FTPdef send_image_to_wu(image):    session = FTP('webcam.wunderground.com', wu_cam_id, wu_cam_pwd)    file = open(image, 'rb')    session.storbinary('image.jpg', file)    file.close()    session.quit()

Однако, даже просто вручную передать данные на WU у меня не получилось ни разу. Судя по форумам техподдержки, данная фича работает плохо и сбоит.

Альтернативной является передача изображения на narodmon.ru,

Собственно, время от времени (раз в полчаса) дёргаем ручку /api/v1/capture_photo (которая зовёт take_photo). Например, будем звать через cron этот bash-скрипт:

#!/bin/bashPATH_TO_PHOTO=`/usr/bin/wget -O - -q -t 1 http://0.0.0.0/api/v1/capture_photo`REQUEST='curl -F YOUR_CAM_KEY=@'$PATH_TO_PHOTO' http://narodmon.ru/post'RESULT=`$REQUEST` >/dev/null 2>&1

На сервисе сразу появится снимок:

Плюс, не забываем время от времени (например раз в семь дней) чистить старые изображения:

#!/bin/bash bash# Notes:# This file will remove all files in camera folder older than 7 days, just run in via cron periodically (i.e. daily).find /home/pi/web-server/camera/ -type f -mtime +7 -name '*.jpg' -execdir rm -- '{}' \;

Что дальше?

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

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

Подробнее..

DIY регистратор молний

15.06.2021 20:16:32 | Автор: admin

Автор: Alex Wulff (из-за глюков хабраредактора не получилось оформить как перевод)

К старту курса о разработке на С++ мы перевели статью о персональном регистраторе молний небольшом устройстве, сообщающем об ударах молнии поблизости. Оно даже сообщает, на каком расстоянии ударила молния; при этом, по словам автора, собрать его самому обойдётся дешевле, чем купить в магазине. Ещё один очевидный плюс вы сможете отточить свои умения в схемотехнике.

В основу устройства положен детектор молний AS3935 с ВЧ-каналом производства DFRobot. Детектор обнаруживает электромагнитное излучение молнии и с помощью специального алгоритма преобразовывает эту информацию в информацию о расстоянии до удара.


Датчик может обнаруживать удары молнии на расстоянии до 40 км (25 миль) и определять расстояние до места удара молнии с точностью до 4 км (2,5 мили). Сам датчик довольно надёжен, но может срабатывать неверно, если устройство находится на открытом воздухе. Самодельное устройство может работать не так надёжно, как коммерческий регистратор молний.

Материалы
  • микроконтроллер-жучок (beetle) DFRobot #DFR0282. Это плата Arduino Leonardo очень малых размеров;

  • Gravity: датчик расстояния до молнии DFRobot #SEN0290;

  • зарядное устройство для литиевых аккумуляторов DFRobot #SEN0290;

  • аккумулятор LiPo, 500 мАч Amazon #B00P2XICJG;

  • пьезодинамик 5В, например Amazon #B07GJSP68S;

  • маленький скользящий переключатель;

  • монтажный провод (одно- или многожильный).

Инструменты
  • компьютер с бесплатным ПО Arduino IDE.

  • паяльник и припой;

  • пистолет для горячего клея;

  • машинка для зачистки концов провода от изоляции;

  • 3D-принтер (не обязательно).

1. Разработка схемы соединений

Схема устройства проста. Информация с датчика молнии передаётся по линиям SCL и SDA, плюс к этому одно соединение предусмотрено для звукового сигнала. Устройство питается от литий-ионного полимерного аккумулятора (LiPo), поэтому я решил встроить в схему зарядное устройство для такой батареи.

Рисунок AРисунок A

Схема устройства показана на рисунке A. Обратите внимание, что аккумуляторная батарея LiPo соединяется с зарядным устройством через штекерно-гнездовые разъёмы JST и не требует пайки.

2. Сборка схемы

Для сборки устройства лучше всего применить так называемую технику свободной сборки. Детали не крепятся к подложке (например к перфорированной плате) а просто соединяются проводами (рис. Б). Так устройство собирается гораздо быстрее и получается меньше по размеру. Правда, страдает эстетика... Но сомнительную эстетику никто не увидит, если сборку закрыть напечатанным на 3D-принтере корпусом. На видео выше показано, как я собрал схему методом свободной сборки.

Подсоедините жучок к зарядному устройству

Отпаяйте зелёные клеммы от зарядного устройства LiPo. Они бесполезны, но занимают пространство. Соедините положительную (+) и отрицательную (-) клеммы зарядного устройства аккумуляторной батареи LiPo с положительной (+) и отрицательной () клеммами на лицевой части жучка. По этим проводам первичное напряжение батареи LiPo будет подаваться непосредственно на микроконтроллер. Технически жучку требуется 5В, но от напряжения 4В батареи LiPo он всё равно будет работать.

Подключение датчика молнии

Обрежьте входящий в комплект четырёхконтактный кабель так, чтобы от провода осталось примерно 5 см. Зачистите концы и подключите кабель к датчику молнии, выполнив следующие соединения:

  • положительную (+) клемму на датчике молнии соедините с положительной (+) клеммой на жучке;

  • отрицательную () клемму на датчике молнии соедините с отрицательной (-) клеммой на жучке;

  • контакт синхронизации (C) на датчике молнии соедините с колодкой SCL на жучке;

  • контакт данных (D) на датчике молнии соедините с колодкой SDA на жучке.

Контакт IRQ на датчике молнии также должен быть соединён с колодкой RX на жучке. Соединение должно подходить к аппаратному прерывателю на жучке; колодка RX (контакт 0) единственный оставшийся контакт, поддерживающий прерывание.

Подключение зуммера

Подключите короткий провод зуммера к отрицательной () клемме на жучке (земля), а длинный провод к контакту 11. Сигнальный вывод зуммера должен быть подключён к выводу PWM (для обеспечения максимальной гибкости), здесь идеально подходит контакт 11.

Подсоединение переключателя

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

Рисунок БРисунок Б

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

Окончательная компоновка

Рисунок ВРисунок В

Последний шаг избавляемся от беспорядочного скопления проводов и компонентов и приводим устройство в более презентабельный вид (рис. В). Это нужно делать аккуратно, чтобы не переломить провода. Приклейте горячим клеем зарядное устройство LiPo к верхней части батареи LiPo, затем сверху приклейте жучок. И последнее действие: приклейте к самому верху датчик молнии. Зуммер я вывел на сторону, как показано на рисунке В. В результате получилось несколько скреплённых между собой плат с торчащими из них проводами. Выводы переключателя я также оставил свободными, чтобы позже вставить их в корпус, распечатанный на 3D-принтере.

3. Программирование микроконтроллера

Запустите на компьютере Arduino IDE и убедитесь, что в меню ToolsBoard (ИнструментыПлата) выбрано значение Leonardo. Загрузите и установите библиотеку для датчика молнии. Затем скачайте код проекта и загрузите его на жучок. Программа предельно проста и очень легко настраивается.

Обнаружив молнию, устройство сначала подаст несколько звуковых сигналов, чтобы предупредить об ударе молнии поблизости, а затем подаст определённое количество звуковых сигналов, соответствующее расстоянию до молнии в километрах. Если молния находится на расстоянии менее 10 км (6,2 мили), детектор подаст один длинный звуковой сигнал. Если расстояние превышает 10 км (6,2 мили), расстояние будет поделено на 10, округлено, и устройство подаст соответствующее полученному числу количество сигналов. Например, если молния ударит на расстоянии 26 км (16 миль), то сигнала будет три.

Программное обеспечение запускается прерываниями от датчика молнии. Когда он обнаружит электромагнитное излучение от удара, на контакт IRQ подаётся высокое напряжение, оно вызывает прерывание в микроконтроллере. Датчик также может посылать прерывания для событий, не связанных с ударом молнии, например при превышении порогового уровня помех/шума.

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

4. Распечатка корпуса на 3D-принтере (не обязательно)

Рисунок ГРисунок ГРисунок ДРисунок ДРисунок ЕРисунок Е

Корпус для устройства разработал я сам. Файлы для 3D-печати можно загрузить здесь. (рис. Г, Д). Верхняя часть корпуса прищёлкивается к нижней, никакого специального оборудования не требуется. Корпус достаточно просторный, чтобы в нём могло поместиться и ваше устройство, если вы будете собирать его по-другому (рис. Д). В любом случае вам ничего не мешает спроектировать аналогичный корпус самому:

  • определите габариты устройства;

  • спроектируйте устройство в программе CAD (мне нравится Fusion 360 студенты могут получить её бесплатно);

  • создайте корпус, перетащив профиль из модели устройства. Допуска в 2 мм будет вполне достаточно.

Обнаружение ударов молнии

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

Заряжать устройство очень просто достаточно подключить microUSB-кабель к зарядному устройству LiPo и дождаться, когда индикатор зарядки загорится зелёным цветом. Во время зарядки устройство должно быть включено, иначе энергия не будет поступать в аккумулятор!

Внесение изменений

Регистратор молнии можно сделать более полезным и удобным в использовании, если внести в программное обеспечение определённые изменения:

  • другие звуковые сигналы: чтобы устройство звучало приятнее, используйте библиотеку звуков Tone.h;

  • спящий режим: микроконтроллер ATmega32u4 (чип, на основе которого работает жучок) поддерживает аппаратные прерывания в спящем режиме. Устройство можно перевести в спящий режим, и любое поступившее от датчика молнии, событие заставит датчик реагировать. Спящий режим может значительно продлить срок службы батареи.

Этот материал показывает, что умение разрабатывать программы на С++, работа с электроникой, даёт широкие возможности и может быть полезна в самых разных сферах: представьте, например, что вы часто бываете на природе тогда о грозе лучше знать заранее и даже за километры, но не нужно дорогого оборудования. Если вам нравится чувствовать, как вы управляете железом, идущим по микросхемам током, то вы можете присмотреться к нашему курсу о разработке на С++, где студенты готовятся к началу карьеры разработчика ПО на этом сложном и мощном языке.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Живые обои для компьютера на Python

30.03.2021 06:04:18 | Автор: admin

Не ругайтесь сильно, программирование - лишь мое хобби, и я только учусь.

Идея ко мне пришла неожиданно, я просто задумался : "хм, а можно же совместить обои и погоду, но почему никто еще так не сделал?" просто даже ради того чтобы сделать.

ВНИМАНИЕ! Речь зайдет о самом проекте как таковом, здесь не будет исходного кода!

Итак, для моего проекта мне понадобилось :

  • Pillow - дабы можно было "генерировать" саму картинку которая и будет обоями

  • Pyautogui - для возможности делать скриншот

  • Pyowm - библиотека предоставляющая узнать погоду

  • Tkinter - чтобы создать какое-никакое окно нашего "приложения"

  • Немножко времени и терпения

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

Как и почему это все работает?

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

  1. папки, файлы и еще раз файлы

    при включении, приложении проверяет наличие папки в корне, если же оно ее не находит - то создает и скачивает в нее все что нужно для работы приложения, и еще раз проверяет ее и все ее внутренности

  2. все так же файлы

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

  3. что же там за окном?

    после всех этих действий, она узнает погоду и просто держит ее в памяти до нужного момента

  4. зависимость от времени, что?

    первым делом, я пожелал поберечь здоровье, а конкретно - глаза. ведь никому не нужно чтобы во время чаепития в 2 часа ночи, этот ужасно яркий рабочий стол заставил наши глаза перейти в жидкое состояние. к чему я клоню? приложение проверяет время на вашем устройстве, и если оно больше 6-ти вечера (т.е. 18:00), и меньше 5-ти утра (т.е. 05:00) то дальнейшая смена обоев будет проходить в "темном режиме", пусть и мелочь, но зато как же это "радует" глаз во всех смыслах.

  5. костыли и не то чтобы велосипеды

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

  6. вас тоже бесит это окно закрывающее обои?

    не стоит забывать, что держать на своем мониторе вечно открытую программу, не делающую практически ничего - как минимум странно , и весьма бесполезно, пусть ее и можно свернуть. но вот незадача, меня раздражает это окно в панели быстрого доступа, оно занимает место, им ведь никто не пользуется. я не знаю как можно здесь обойтись без возможности "свернуть" в трей, просто щелкаем на красный крестик иииии да! теперь я вижу обещанную погоду на своих обоях, и при этом ничего и нигде не занимает просто так место. к тому же, если мне будет лень свернуть браузер во время просмотра того же ютуба , я всегда могу просто навести курсор на иконку в трее, и узнать погоду!

  7. Как по мне, это хоть капельку да полезно и познавательно

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

Конечный результат:

прошу простить, но скриншот с белым фоном остался лишь со времен разработки, т.к. в последние времена компьютер я включаю лишь ближе к ночи (к слову, я очень долго думал , писать пост или нет)

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

Спасибо за внимание Хабр, удачи вам!

Подробнее..

Снежная слепота беспилотных авто

02.06.2021 10:16:01 | Автор: admin


У природы нет плохой погоды, каждая погода благодать. Слова этой лирической песни можно понимать образно, интерпретировав погоду как отношения между людьми. Можно понимать и буквально, что также верно, ибо не было бы снежной и холодной зимы, мы бы не так ценили лето, и наоборот. Но беспилотные автомобили лишены лирических чувств и поэтического мироощущения, для них далеко не вся погода благодать, особенно зимняя. Одной из основных проблем, с которыми сталкиваются разработчики робомобилей, это снижение точности датчиков, указывающих машине куда ей ехать, во время плохих погодных условий. Ученые из Мичиганского технологического университета создали базу данных погодных условий на дорогах глазами беспилотных авто. Эти данные были нужны дабы понять что нужно изменить или улучшить, чтобы зрение робомобилей во время снежной бури было не хуже, чем в ясный летний день. Насколько плохая погода влияет на датчики беспилотных авто, какой метод решения проблемы предлагают ученые, и насколько он эффективен? Ответы на эти вопросы мы найдем в докладе ученых. Поехали.

Основа исследования


Работу беспилотных авто можно сравнить с уравнением, в котором очень много переменных, которые нужно учесть все без исключения для получения верного результата. Пешеходы, другие авто, качество дорожного покрытия (видимость разделительных полос), целостность систем самого беспилотника и т.д. Многие исследования ученых, провокационные заявления политиков, колкие статьи журналистов базируются на связи между беспилотным автомобилем (далее просто авто или автомобиль) и пешеходом. Это вполне логично, ибо человек и его безопасность должны стоять на первом месте, особенно учитывая непредсказуемость его поведения. Морально-этические споры о том, кто будет виноват, если автомобиль собьет пешехода, выскочившего на дорогу, продолжаются до сих пор.

Однако, если убрать из нашего образного уравнения переменную пешеход, то все равно останется много потенциально опасных факторов. Погода является одним из них. Очевидно, что в плохую погоду (ливень или снежная буря) видимость может снизиться настолько, что порой приходится просто остановиться, ибо ехать нереально. Зрение автомобилей, конечно, сложно сравнить со зрением человека, но их датчики страдают от снижения видимости не меньше нас. С другой стороны у машин есть более широкий арсенал этих датчиков: камеры, радары диапазона миллиметровых волн (MMW), система глобального позиционирования (GPS), гиростабилизатор (IMU), система обнаружение и определение дальности с помощью света (LIDAR) и даже ультразвуковые системы. Несмотря на это многообразие органов чувств, автономные машины все еще слепы во время плохой погоды.

Дабы понять, в чем же дело, ученые предлагают рассмотреть аспекты, совокупность которых тем или иным образом влияет на возможное решение этой проблемы: семантическая сегментация, обнаружение проходимого (подходящего) пути и объединение датчиков.

При семантической сегментации вместо обнаружения объекта на изображении каждый пиксель классифицируется индивидуально и присваивается классу, который пиксель представляет лучше всего. Другими словами, семантическая сегментация это классификация на уровне пикселей. Классическая семантическая сегментация сверточная нейронная сеть (CNN от convolutional neural network) состоит из кодирующей и декодирующей сетей.

Кодирующая сеть понижает дискретизацию входных данных и извлекает функции, а декодирующая использует эти функции для восстановления и повышения дискретизации входных данных и, наконец, присваивает каждому пикселю тот или иной класс.

Двумя ключевыми компонентами в декодирующих сетях являются так называемые слой MaxUnpooling и слой свертки Transpose. Слой MaxUnpooling (аналог слоя MaxPooling операция пулинга с функцией максимума) необходим для снижения размерности обрабатываемых данных.


Пример операции MaxPooling.

Существует несколько методов распределения значений (т.е. пуллинга), которые имеют общую цель сохранить местоположения максимальных значений в слое MaxPooling и использовать эти местоположения для размещения максимальных значений обратно в совпадающие местоположения в соответствующем слое MaxUnpooling. Этот подход требует, чтобы сеть кодирования-декодирования была симметричной, в которой каждый уровень MaxPooling в кодере имеет соответствующий уровень MaxUnpooling на стороне декодера.

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

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

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

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

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

Третий, но не менее важный, аспект это объединение датчиков. Под этим подразумевается буквальное объединение данных от нескольких датчиков для получения более полной картины и уменьшения вероятных погрешностей и неточностей в данных отдельных датчиков. Существует однородное и неоднородное объединение датчиков. Примером первого может быть использование нескольких спутников для уточнения местоположения по GPS. Примером второго является объединение данных камер, LiDAR и Radar для беспилотных авто.

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


Таблица преимуществ и недостатков датчиков, используемых в беспилотных авто.

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

Сбор данных


В данном исследовании, как уже упоминалось ранее, были использованы сверточные нейронные сети и объединение датчиков для решения проблемы обнаружения пути, по которому можно проехать, в неблагоприятных погодных условиях. Предлагаемая модель представляет собой многопотоковую (по одному потоку на датчик) глубокую сверточную нейронную сеть, которая будет понижать дискретизацию карт функций (результат применения одного фильтра к предыдущему слою) каждого потока, объединять данные, а затем повторно повышать дискретизацию карт для выполнения попиксельной классификации.

Для проведения дальнейших работ, включающих расчеты, моделирование и тестирование, необходимо было много данных. Чем больше, тем лучше, говорят сами ученые, и это вполне логично, когда речь идет о работе различных датчиков (камеры, LiDAR и Radar). Среди множества уже существующих наборов данных был выбран DENSE, которые охватывает большую часть необходимых для исследования нюансов.

DENSE также является проектом, нацеленным на решение проблем нахождения пути в суровых погодных условиях. Ученые, работавшие над DENSE, проехали порядка 10000 км по Северной Европе, записывая данные с нескольких камер, нескольких LiDAR, радаров, GPS, IMU, датчиков дорожного трения и тепловизионных камер. Набор полученных данных состоит из 12000 выборок, которые можно разбить на более мелкие подгруппы, описывающие конкретные условия: день+снег, ночь+туман, день+ясно и т.д.

Однако для правильной работы модели необходимо было провести коррекцию данных из DENSE. Исходные изображения камеры в наборе данных имеют размер 1920 х 1024 пикселей, их уменьшили до 480 х 256 для более быстрого обучения и тестирования модели.

Данные LiDAR хранятся в формате массива NumPy, который нужно было преобразовать в изображения, масштабировать (до 480 x 256) и нормализовать.

Данные радара хранятся в файлах JSON, по одному файлу для каждого кадра. Каждый файл содержит словарь обнаруженных объектов и несколько значений для каждого объекта, включая x-координаты, y-координаты, расстояние, скорость и т.д. Такая система координат параллельна плоскости автомобиля. Чтобы преобразовать ее в вертикальную плоскость, нужно учитывать только y-координату.


Изображение 1: проецирование y-координаты на плоскость изображения (слева) и обработанный кадр радара (справа).

Полученные изображения подвергались масштабированию (до 480 x 256) и нормализации.

Разработка CNN модели



Изображение 2: архитектура разработанной CNN модели.

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

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

Данные LiDAR не столь массивны, как данные от камер, потому его поток состоит из трех блоков. Точно так же поток Radar меньше, чем поток LiDAR, потому состоит всего из двух блоков.

Выходные данные от всех потоков изменяются и объединяются в одномерный вектор, который подключен к сети из трех скрытых слоев с ReLU активацией. Затем данные преобразуются в двумерный массив, который передается в сеть декодирования, состоящую из четырех последовательных этапов MaxUnpooling и транспонированной свертки для повышения дискретизации данных до размера ввода (480x256).

Результаты обучения/тестирования CNN модели


Обучение и тестирование проводились на Google Colab с использованием GPU. Подмножество данных, размеченных вручную, состояло из 1000 выборок данных камеры, LiDAR и радара 800 для обучения и 200 для тестирования.


Изображение 3: потери в обучающих выборках во время фазы обучения.

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


Изображение 4: точность в тестовых выборках во время фазы тестирования.

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

Однако этот показатель не является идеальным. В некоторых случаях определенный класс недостаточно представлен в выборке, от чего точность пикселей будет значительно выше (чем на самом деле) из-за того, что не хватает пикселей для тестирования модели для определенного класса. Посему было решено дополнительно использовать MIoU среднее отношение области пересечения к области объединения.


Визуально представление IoU.

Подобно точности пикселей, точность по IoU вычисляется для каждого кадра, а конечный показатель точности это среднее от этих значений. Однако MIoU рассчитывается для каждого класса отдельно.


Таблица значений точности.


Изображение 5

На изображении выше показаны четыре выбранных кадра движения по снегу с камеры, LiDAR, радара, наземных данных и выходных данных модели. Из этих изображений очевидно, что модель может очертить общую окружность области, в которой транспортное средство может безопасно двигаться. Модель при этом игнорирует какие-либо линии и края, которые в противном случае можно было бы интерпретировать как края проезжей части. Модель также показывает хорошие результаты в условиях пониженной видимость (например, во время тумана).

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

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

Эпилог


Отношение к беспилотным автомобилям неоднозначное. С одной стороны, робомобиль нивелирует такие риски, как человеческий фактор: нетрезвый водитель, лихачество, безответственное отношение к ПДД, малый опыт вождения и т.д. Другими словами, робот не ведет себя как человек. Это хорошо, так ведь? И да, и нет. Во многом автономные транспортные средства превосходят водителей из плоти и крови, но далеко не во всем. Плохая погода тому яркий пример. Человеку, конечно, непросто ехать во время снежной бури, но для беспилотных авто это было практически нереально.

В данном труде ученые обратили внимание на эту проблему, предложив сделать машины немного человечнее. Дело в том, что у человека тоже есть датчики, которые работают командно для того, чтобы он получал максимум информации об окружающей среде. Если датчики беспилотного авто также будут работать как единая система, а не как отдельные ее элементы, можно будет получить больше данных, т.е. повысить точность нахождения проходимого пути.

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

Благодарю за внимание, оставайтесь любопытствующими и хорошей всем рабочей недели, ребята. :)

Немного рекламы


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Maincubes Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?
Подробнее..

Погодозависимый бизнес

21.11.2020 20:20:09 | Автор: admin


Как определить, является ли концепция Индустрии 4.0 повинностью компании перед модным трендом или логическим продолжением идей развития бизнеса?

Индикатором является учет погоды в организации бизнеса. С погодой все просто: есть много датчиков, станций наблюдения и как, не смешно, предиктивная аналитика в виде прогноза на разные временные горизонты. Кроме того, имеются исторические данные, из которых можно выделить корреляцию производственно-коммерческих индикаторов работы компании с погодой.
Инстаграм

Явно погодозависимым является около 60-70% бизнеса. Если считать больничные для работников и по уходу за детьми, то процент будет еще больше.

Кроме погодозависимости бизнеса, еще имеет место погодозависимость в потреблении продукции бизнеса.

Для угля это отклонения в жару и холод. Для производителей удобрений засуха или дожди. Для аграрного сектора и фермерских хозяйств каждый тип погодных явлений требует соответствующей реакции.

Если промышленные компании хотят попробовать на практике достижения Индустрии 4.0 при минимуме вложений, то введение в рассмотрение фактора погодозависимости самый лучший вариант. Ставить на погодозависимость при существующем уровне эффективности не самый лучший вариант. Есть много других сфер, гарантирующих присутствие значительно больших резервов повышения эффективности.

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

1. Искусственный интеллект на практике


Свыше нам дали турбулентность. Пока нет уравнений описывающих турбулентность. Достаточно достоверный прогноз погоды даётся только на 3 дня, что является следствием медленной скорости и инертности воздушных потоков.

Погодные станции расположены достаточно далеко друг от друга. В США эту проблему частично решили, подключив более 40 000 частных погодных станций в общую сеть.

Турбулентность проявляется на практике в том, что в зависимости от конфигурации местности и движения воздушных потоков, значения показателей может отличаться на расстоянии 100-200 метров.

Для привязанных к местности погодных станций существует решение по увеличению точности прогноза на базе машинного обучения (искусственного интеллекта). На основе собираемой в данной точке статистики в текущий официальный прогноз вносятся коррекции, которые учитывают конфигурацию ландшафта в этой точке.

2. Раз природа переходим на лунный календарь


Далее приведены данные для метеостанции Малое Сареево. Основная масса станций расположена далеко друг от друга по расходящимся от Москвы кругам. Единственный вариант, когда станции расположены достаточно близко и соответствуют вершинам треугольника с ребрами в 17-20 км это Малое Сареево, Немчиновка и аэродромная станция Внуково. В этом случае можно хоть как-то перепроверять получаемые результаты.
Малое Сареево: температурные данные (фрагмент данных с 2005 по 2017, дневные линии синии, ночные коричневые):



Все измерения, во-первых, были разбиты на периоды соответствующие лунному месяцу и полупериоды роста и убывания луны. Во-вторых, внутри измерений одного дня были сгруппированы измерения на ночные и дневные по времени восхода и захода солнца, а также перенормированы на единичный интервал.

Перенормирование на единичный интервал необходимо в связи с тем, что полупериоды могут отличаться на 1-2 дня и в сутках постоянно перемещается граница день-ночь.

3. BigData это нелинейность


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

Остается только экспериментировать и развивать интуицию.

Исходные данные были сглажены через скользящее среднее. В рамке из 4-х картинок:

верхний ряд:
левый рисунок: исходный день(синий)-исходная ночь (коричневая),
правый рисунок: сглаженный день(синий)-сглаженная ночь(коричневая);
нижний ряд:
левый рисунок: исходный день(синий)-сглаженный день(коричневый),
правый рисунок: исходная ночь(синий)-сглаженная ночь(коричневый).

Совмещение дня и ночи очень сильно сбивает картину из-за сложности динамики. Разделение дня и ночи (трудности с плавающей границей рассвет-закат) позволяет видеть практически одинаковый профиль с небольшим смещением (верхний ряд правый рисунок).



4. Близкие профили: сезонные и межсезонные


Полученные профили можно сравнивать. В качестве метрики используем значение интеграла абсолютного значения всех пар функций. Для Малого Сареева имеем 83 лунных полупериода с 2012 по 2017 годы. Распределений округленных значений метрики приведены в таблицах.



Этим значениям соответствует следующее распределение.



Ниже на рисунке приведена сезонная интерференционная картина: за 4 года для Малого Сареева для дневных профилей. Матрица 83х83. В рамках введенной метрики прослеживается некая периодичность.



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

Одинаковые профили с разной температурой не будут близкими. Будем использовать другую метрику: интеграл от абсолютного значения разности функций со смещением на расстояния средней разницы между функциями по 10 точкам. Будем называть такие профили межсезонными.

Распределение становится более определенным первое сезонное, второе межсезонное.



Вторая интерференционная картина также более четкая.



5. Что получилось и что это дает?


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

Что нового дают полученные результаты? Исходя из них можно типизировать прогноз и понимать, по каким профилям он может развиваться, а по каким развитие маловероятно.

6. Туман на аэродромах


Следующий пример демонстрирует явную пользу типизации профилей.

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

Имеются устройства, которые периодически измеряют температуру через 50 метров до 1000 метров в высоту (всего 20 измерений).

По той же схеме, что и ранее выделяем типовые профили (фрагмент).



Сведенные справа профили по виду могут отличаться от расположенных слева из-за разной размерности шкалы.

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



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

7. Выводы


Если промышленные компании хотят попробовать на практике достижения Индустрии 4.0 при минимуме вложений, то введение в рассмотрение фактора погодозависимости самый лучший вариант. Ставить на погодозависимость при существующем уровне эффективности не самый лучший вариант. Есть много других сфер, гарантирующих присутствие значительно больших резервов повышения эффективности.

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

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru