Реклама ⓘ
Главная » Компьютерная электроника
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Похожие статьи:


Реклама ⓘ

Интерактивный экран-помощник

Изначально, я хотел написать обучающую статью по экрану Nextion, но потом понял, что этого добра навалом в Интернете и желание само собой улетучилось. Вдохновленный одним известным в наших кругах человеком, я решил собрать себе устройство с мониторингом событий на своем youtube канале. Для этого я решил собрать комплект из миникомпьютера Omega 2 и экрана Nextion. В дальнейшем, я смогу изменить задачу этой конструкции, а сейчас душа требует свершений. Я настолько вдохновился, что и ролик сделал, внизу к статье его прикрепил. Приступаем к работе.

Давайте сразу приведу схематичный вид устройства. 

Все просто. К самой омеге подпаиваем USB разъем для флешки и выход со второго UART'а. Блок питания 5 В, для получения 3.3 В ставим конвертор напряжения. Я использовал LM317, но это не лучший вариант, лучше - LM2596 или MP2307. К экрану Nextion подпаиваем 5 В.

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

Подключаем к Omega 2 датчик температуры и влажности HIH6130 и работаем с облаком Azure: https://youtu.be/kabWcZriVCE 
Честный обзор миникомпьютера OMEGA 2: https://youtu.be/7MDKTXhi5lI 

Теперь надо подключить к Omega 2 ненужную флешку, чтобы увеличить на 5 см объем памяти для установки различных пакетов. Как это сделать очень просто рассказано по следующим ссылкам:

1. Монтирование флешки: https://goo.gl/eqoKZM

2. Создание swap файла для распаковки некоторых пакетов: https://goo.gl/C69tVD

Swap файл увеличит объем оперативной памяти omega для распаковки некоторых пакетов при установке (например http модуль python'а не установиться без swap файла - проверено). 

Теперь будем устанавливать все приложения! В данном моменте я уже считаю, что вы включили омегу, подключились к ней по SSH (пароль - onioneer) и к вашей wifi точке доступа с помощью команды wifisetup. Для начала надо обновить информацию о пакетах:

opkg update

Далее устанавливаем MC (файловый менеджер), NANO (текстовый редактор), PYTHON и PIP:

opkg install mc nano python python-pip

Далее поставим пакет для общения через UART в питоне:

opkg install python-serial

и кучу всяких библиотек которые нам понадобятся:

pip install google-auth google-auth-oauthlib google-auth-httplib2 requests httplib2

Теперь открываем Nextion Editor. И тут опять же есть, что посмотреть по экранам Nextion, чтобы набраться знаний:

Что могут дисплеи Nextion? Обзор возможностей, примеры использования: https://youtu.be/gNqT4LRnNC4 
Графический замок на дисплее Nextion HMI: https://youtu.be/p-PbTNAlY8c 

Нам необходимо реализовать 2 странички. На первой будет выводиться информация по вашему youtube каналу, на второй будет выводиться время, дата и погода в вашем любимом городе. Я решил выводить следующую информацию: общее количество подписчиков, прирост подписчиков за час, последние пять комментариев на канале. Для этого надо поставить два числовых поля и 5 текстовых. При нажатии на любую часть экрана интерфейс должен переходить на следующую страничку сразу реализуем это, добавив в события Press Event всех элементов на странице следующий код:

page time

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

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

#!/usr/bin/python
# -*- coding: utf-8 -*-

import httplib2
import os
import sys
import serial
import time
from datetime import datetime
import requests

from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow

# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
# the OAuth 2.0 information for this application, including its client_id and
# client_secret.
CLIENT_SECRETS_FILE = "client_secrets.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.force-ssl"
API_SERVICE_NAME = "youtube"
API_VERSION = "v3"

# This variable defines a message to display if the CLIENT_SECRETS_FILE is
# missing.
MISSING_CLIENT_SECRETS_MESSAGE = "WARNING: Please configure OAuth 2.0" 

# Authorize the request and store authorization credentials.
def get_authenticated_service(args):
  flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_SCOPE,
    message=MISSING_CLIENT_SECRETS_MESSAGE)

  storage = Storage("youtube-api-snippets-oauth2.json")
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, args)

  # Trusted testers can download this discovery document from the developers page
  # and it should be in the same directory with the code.
  return build(API_SERVICE_NAME, API_VERSION,
      http=credentials.authorize(httplib2.Http()))

args = argparser.parse_args()
service = get_authenticated_service(args)

def print_results(results):
  print(results)

# Build a resource based on a list of properties given as key-value pairs.
# Leave properties with empty values out of the inserted resource.
def build_resource(properties):
  resource = {}
  for p in properties:
    # Given a key like "snippet.title", split into "snippet" and "title", where
    # "snippet" will be an object and "title" will be a property in that object.
    prop_array = p.split('.')
    ref = resource
    for pa in range(0, len(prop_array)):
      is_array = False
      key = prop_array[pa]
      # Convert a name like "snippet.tags[]" to snippet.tags, but handle
      # the value as an array.
      if key[-2:] == '[]':
        key = key[0:len(key)-2:]
        is_array = True
      if pa == (len(prop_array) - 1):
        # Leave properties without values out of inserted resource.
        if properties[p]:
          if is_array:
            ref[key] = properties[p].split(',')
          else:
            ref[key] = properties[p]
      elif key not in ref:
        # For example, the property is "snippet.title", but the resource does
        # not yet have a "snippet" object. Create the snippet object here.
        # Setting "ref = ref[key]" means that in the next time through the
        # "for pa in range ..." loop, we will be setting a property in the
        # resource's "snippet" object.
        ref[key] = {}
        ref = ref[key]
      else:
        # For example, the property is "snippet.description", and the resource
        # already has a "snippet" object.
        ref = ref[key]
  return resource

# Remove keyword arguments that are not set
def remove_empty_kwargs(**kwargs):
  good_kwargs = {}
  if kwargs is not None:
    for key, value in kwargs.iteritems():
      if value:
        good_kwargs[key] = value
  return good_kwargs

print("Start.../n")

#open UART
ser = serial.Serial('/dev/ttyS1',9600)
print(ser.name)

#get weather
def weather():
  s_city = "Irkutsk,RU"
  city_id = 2023469
  appid = "ваш id с сайта погоды"
  try:
    res = requests.get("http://api.openweathermap.org/data/2.5/weather",
                 params={'id': city_id, 'units': 'metric', 'lang': 'ru', 'APPID': appid})
    data = res.json()
   # print "conditions: ", data['weather'][0]['description']
    ser.write('condition.txt="'+data['weather'][0]['description'].encode('koi8-r')+'"')
    ser.write('\xFF')
    ser.write('\xFF')
    ser.write('\xFF')
   # print datetime.fromtimestamp(int(data['dt']))
   # print "Temp:", data['main']['temp']
    ser.write('grad.txt="'+str(data['main']['temp'])+'"')
    ser.write('\xFF')
    ser.write('\xFF')
    ser.write('\xFF')
   # print "davlenie", data['main']['pressure']
   # print "Vlajnost", data['main']['humidity']
  except Exception as e:
    print("Exception (weather):", e)
    pass

#get trend of subcribes
def send_fucking_number(number):
  file=open("save_subs.txt")
  save_subs_str=file.read()
  file.close()
  old_number=int(save_subs_str)
  print old_number
  ser.write('dsub.val='+str(number-old_number))
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')

#get count of subs
def channels_list_by_id(service, **kwargs):
  kwargs = remove_empty_kwargs(**kwargs) # See full sample for function
  results = service.channels().list(**kwargs).execute()
  subs_count=int(results['items'][0]['statistics']['subscriberCount'])
  ser.write('sub_count.val=')
  ser.write(str(subs_count))
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')
  send_fucking_number(subs_count)

#get of list of comments
def comment_threads_list_all_threads_by_channel_id(service, **kwargs):
  kwargs = remove_empty_kwargs(**kwargs) # See full sample for function
  results = service.commentThreads().list(
    **kwargs
  ).execute()

  #print_results(results['items'][0]['snippet']['topLevelComment']['snippet']['textOriginal'])
  ser.write('t0.txt="'+results['items'][0]['snippet']['topLevelComment']['snippet']['textOriginal'][0:127].encode('koi8-r').replace('"', '$')+'"')
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')
# print_results(results['items'][1]['snippet']['topLevelComment']['snippet']['textOriginal'])
  ser.write('t1.txt="'+results['items'][1]['snippet']['topLevelComment']['snippet']['textOriginal'][0:127].encode('koi8-r').replace('"', '$')+'"')
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')
 # print_results(results['items'][2]['snippet']['topLevelComment']['snippet']['textOriginal'])
  ser.write('t2.txt="'+results['items'][2]['snippet']['topLevelComment']['snippet']['textOriginal'][0:127].encode('koi8-r').replace('"', '$')+'"')
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')
 # print_results(results['items'][3]['snippet']['topLevelComment']['snippet']['textOriginal'])
  ser.write('t3.txt="'+results['items'][3]['snippet']['topLevelComment']['snippet']['textOriginal'][0:127].encode('koi8-r').replace('"', '$')+'"')
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')
 # print_results(results['items'][4]['snippet']['topLevelComment']['snippet']['textOriginal'])
  ser.write('t4.txt="'+results['items'][4]['snippet']['topLevelComment']['snippet']['textOriginal'][0:127].encode('koi8-r').replace('"', '$')+'"')
  ser.write('\xFF')
  ser.write('\xFF')
  ser.write('\xFF')

subs_count=0

channels_list_by_id(service,
    part='snippet,contentDetails,statistics',
    id='ваш id')
comment_threads_list_all_threads_by_channel_id(service,
    part='snippet,replies',
    allThreadsRelatedToChannelId='ваш id')
weather()

Первая часть скрипта была нагло скопирована с примеров работы с youtube API на github'е: https://github.com/youtube/api-samples/tree/master/python

Там можно подсмотреть и работу с другими функциями сайта.

Функция ser.write() отправляет в uart данные. Чтобы вывести в числовое поле экрана значение мы должны отправить команду следующего вида:

n0.val=X0xFF0xFF0xFF

где n0 имя числового поля, X значение, которое мы хотим отправить.

Для текстового поля:

t0.txt="строка"0xFF0xFF0xFF

где t0 имя текстового поля.

Любая команда завершается тремя байтами FF, поэтому при отправке комментариев, я заменяю в них двойные кавычки на знак доллара, чтобы не было ошибок.

Собственно, чтобы у вас заработали эти скрипты вы должны получить youtube key: http://code.google.com/apis/youtube/dashboard/

и пройти регистрацию на сайте погоды и получить там key: https://home.openweathermap.org/users/sign_up

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

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

cd /root

python minutes.py

Переходим в папку со скриптами и запускаем скрипт. После этого открываем таблицу задач:

nano /etc/crontabs/root

И создаем две задачи:

1-59/1 * * * * * /root/boot_min.sh

0 * * * * * /root/boot_h.sh

Первая команда запускает каждую минуту с первой по 59 минуты скрипт boot_min.sh, вторая запускает в 0 минуту скрипт boot_h.sh. Главное не забыть сделать эти скрипты запускаемыми chmod +x /root/boot-min.sh

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

Купить миникомпьютер Omega 2 в России удобней всего на сайте Амперо: http://ampero.ru/collection/omega-2 Лично я советую присмотреться к вариантам с маркировкой S (Omega 2S и Omega 2S Plus). У них исполнение SMD, а значит их удобней паять и больше полезных выводов.

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

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

Прикрепленные файлы:

Теги:

Опубликована: 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (1) | Я собрал (0) | Подписаться

0
Публикатор #
На форуме автоматически создана тема для обсуждения статьи.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

USB-реле (2 канала)
USB-реле (2 канала)
Программатор Pickit3 Конструктор - темброблок на LM1036
вверх