[PYTHON] Anzeigen von Wettervorhersagen auf M5Stack + Google Cloud Platform

Mein Name ist Niamugi und ich bin verantwortlich für den 4. Tag des IoTLT-Adventskalenders 2019. "Anzeigen der Wettervorhersage auf M5Stack" ist ein sehr solider Inhalt, aber ich möchte ihn einführen, da ein vielseitiger Mechanismus erstellt wurde. ** Es ist beliebt bei meiner Familie und ich bin froh, dass es täglich verwendet wird. ** **.

Aussehen

Zeigt die Wettervorhersage für die letzten 3 Tage an. Das Wetterzeichen wurde von meinem ältesten Sohn geschrieben. WeatherImg.png

Es wird so angezeigt. WeatherImg_mini.gif

Wie es funktioniert

Das Wettervorhersagebild ist in "** generieren " und " erwerben **" unterteilt.

  1. Führen Sie regelmäßig die Funktion "Generieren von Wettervorhersagebildern" im Cloud Scheduler der Google Cloud Platform (GCP) aus.
  2. Erstellen Sie ein Wettervorhersagebild mit den Cloud-Funktionen von GCP und speichern Sie es in Google Drive.
  3. Führen Sie die "Funktion zum Abrufen des Bildes der Wettervorhersage" in der http-Anforderung von M5Stack aus, um das Bild abzurufen. flow_m5stackImg.png

(Details) Informationen zur Bilderzeugung

Ich werde die Punkte aufzählen.

Holen Sie sich die Wettervorhersage

Ich erhalte Daten, indem ich auf Wettervorhersage der Wetterbehörde zugreife.

Behandeln Sie Dateien mit Cloud-Funktionen

Wenn Cloud-Funktionen, die in der Cloud ausgeführt werden, Ihre Dateien verarbeiten sollen, können Sie sie im Ordner / tmp speichern. Mit anderen Worten, indem Sie die von Google Drive erhaltene Datei im Ordner / tmp speichern, können Sie die Datei auf dieselbe Weise wie in der lokalen Umgebung behandeln.

Vorbereiten des Zugriffs auf Google Drive

Besorgen Sie sich die für den Zugriff erforderliche Client-ID, das Client-Geheimnis und das Aktualisierungstoken im Voraus. Ich habe darüber zuvor im Blog von dot studio geschrieben. [Hochladen von Daten von NefryBT auf Google Drive](https://dotstud.io/blog/update-nefrybt-to-googledrive/#%E3%82%A2%E3%83%83%E3%83%97% E3% 83% AD% E3% 83% BC% E3% 83% 89% E3% 81% BE% E3% 81% A7% E3% 81% AE% E6% 89% 8B% E9% A0% 86 )Bitte beziehen Sie sich auf.

Google Drive betreiben

Funktion, mit der der Dienst auf Google Drive zugreifen kann

Fordern Sie den Dienst auf, mit der Client-ID, dem Client-Geheimnis und dem Aktualisierungstoken auf Google Drive zuzugreifen. Ich bezog mich auf "Python-Aktualisierungstoken Google API: Anmeldeinformationen vom Aktualisierungstoken mithilfe von oauth2client.client abrufen".

def getDriveService():
    CLIENT_ID = os.getenv("drive_client_id")
    CLIENT_SECRET = os.getenv("drive_client_secret")
    REFRESH_TOKEN = os.getenv("drive_refresh_token")

    creds = client.OAuth2Credentials(
        access_token=None,
        client_id=CLIENT_ID,
        client_secret=CLIENT_SECRET,
        refresh_token=REFRESH_TOKEN,
        token_expiry=None,
        token_uri=GOOGLE_TOKEN_URI,
        user_agent=None,
        revoke_uri=None,
    )
    http = creds.authorize(httplib2.Http())

    creds.refresh(http)
    service = build("drive", "v3", credentials=creds, cache_discovery=False)
    return service

Funktion zum Suchen nach Dateinamen und Abrufen der ID

Allen Daten in Google Drive werden IDs zugewiesen. Die ID-Suche ist erforderlich, um Daten anhand der ID zu erfassen und zu aktualisieren.

def searchID(service, mimetype, nm):
    """Suchen Sie eine passende ID von Drive
    """
    query = ""
    if mimetype:
        query = "mimeType='" + mimetype + "'"

    page_token = None
    while True:
        response = (
            service.files()
            .list(
                q=query,
                spaces="drive",
                fields="nextPageToken, files(id, name)",
                pageToken=page_token,
            )
            .execute()
        )

        for file in response.get("files", []):
            if file.get("name") == nm:
                return True, file.get("id")

        page_token = response.get("nextPageToken", None)
        if page_token is None:
            break

Funktion zum Abrufen von Schriftdaten

Cloud-Funktionen werden in der Cloud ausgeführt, sodass Sie wahrscheinlich keine japanischen Schriftarten verwenden können. (Ich habe es nicht versucht) Holen Sie sich also die Schriftart von Google Drive. Der Mimetyp ist "application / octat-stream".

def getFontFromDrive(service, fontName):
    """Holen Sie sich Schriftarten von Drive und speichern Sie sie im tmp-Ordner
    """
    ret, id = searchID(service, "application/octet-stream", fontName)
    if not ret:
        return None

    request = service.files().get_media(fileId=id)
    fh = io.FileIO("/tmp/" + fontName, "wb")  #Datei

    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while done is False:
        status, done = downloader.next_chunk()

    return "/tmp/" + fontName

Funktion zum Abrufen von Bilddaten

Holen Sie sich das Wetterzeichen. Mimetyp ist "image / png".

def getImageFromDrive(service, imageName):
    """Holen Sie sich das Image von Drive und speichern Sie es im tmp-Ordner
    """
    ret, id = searchID(service, "image/png", imageName)
    if not ret:
        return False

    request = service.files().get_media(fileId=id)
    fh = io.FileIO("/tmp/" + imageName, "wb")  #Datei

    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while done is False:
        status, done = downloader.next_chunk()

    return True

Funktion zum Hochladen von Bilddaten

Laden Sie das generierte Wettervorhersagebild auf Google Drive hoch.

def uploadData(service, mimetype, fromData, toData, parentsID="root"):
    """Auf Laufwerk hochladen
    """
    try:
        media = MediaFileUpload(fromData, mimetype=mimetype, resumable=True)
    except FileNotFoundError:
        return False

    #Suchen Sie nach ID und überschreiben Sie diese, wenn zutreffende Daten vorhanden sind.
    ret, id = searchID(service, mimetype, toData)
    if ret:
        file_metadata = {"name": toData}

        file = (
            service.files()
            .update(fileId=id, body=file_metadata, media_body=media, fields="id")
            .execute()
        )
    else:
        file_metadata = {"name": toData, "parents": [parentsID]}

        file = (
            service.files()
            .create(body=file_metadata, media_body=media, fields="id")
            .execute()
        )

    return True

Eine Reihe von Flüssen

Verwenden Sie die oben vorbereitete Funktion, um das Wettervorhersagebild auf Google Drive hochzuladen.

def CreateImgWeather(event, context):
    """ get weatherImage and upload to drive for M5stack
    """

    # 1.Holen Sie sich einen Dienst, um auf Google Drive zuzugreifen
    driveService = getDriveService()

    # 2.Schriftart abrufen
    fontPath = getFontFromDrive(driveService, "meiryo.ttc")
    if not fontPath:
        return False

    # 3.Holen Sie sich das Wetterzeichen
    if not getImageFromDrive(driveService, "noImage.png "):
        return False
    if not getImageFromDrive(driveService, "fine.png "):
        return False
    if not getImageFromDrive(driveService, "cloud.png "):
        return False
    if not getImageFromDrive(driveService, "rain.png "):
        return False
    if not getImageFromDrive(driveService, "snow.png "):
        return False

    # 4.Wettervorhersagebild generieren
    weatherList = getWeekWeather()
    ret = createImg(fontPath, "/tmp/imgWeather.jpeg ", weatherList)
    if not ret:
        return False

    # 5.Auf Google Drive hochladen
    ret = uploadData(
        driveService, "image/jpeg", "/tmp/imgWeather.jpeg ", "imgWeather.jpeg "
    )
    if not ret:
        return False

    return True

(Details) Informationen zur Bildaufnahme

M5Stack Seite

Weitere Informationen finden Sie unter Quelle.

Zugriff auf Cloud-Funktionen funktioniert mit einer http-POST-Anforderung. Dies ist auch dotstudios "Anfrage über HTTP-Kommunikation senden" Ich habe es als Referenz verwendet.

[Hostname] = "[Projektname].cloudfunctions.net"
[Funktionsname] = "getDriveImage_M5stack";
[Port-Nummer] = 443;
      
POST /[Funktionsname] HTTP/1.1
Host: [Hostname]:[Port-Nummer]
Connection: close
Content-Type: application/json;charset=utf-8
Content-Length:  + [Größe der zu postenden JSON-Daten]

[Json Daten zu posten]

Stellen Sie die folgende Anfrage im JSON-Datenformat.

{
  "drive" : {
    "img" : "[Dateiname]",
    "trim" : "[Geteilte Nummer]"
  }
}

Aufgrund der Datenmenge, die gleichzeitig erfasst werden kann, ist sie in 8 Teile unterteilt. Daher wird 8 Mal eine POST-Anfrage gestellt.

Seite der Cloud-Funktionen

Erfasst das Wettervorhersagebild gemäß der POST-Anforderung von M5Stack. Dann werden die in 8 Teile unterteilten Binärdaten zurückgegeben.

Ich werde die Quelle setzen.

import sys
import os
import io
from io import BytesIO
import numpy as np
from PIL import Image

import httplib2
from googleapiclient.discovery import build
from oauth2client import client, GOOGLE_TOKEN_URI
from apiclient.http import MediaIoBaseDownload


def getDriveService():
    ~Gleich wie Bilderzeugung~

def searchID(service, mimetype, nm):
    ~Gleich wie Bilderzeugung~


def downloadData(mimetype, data):
    #Holen Sie sich einen Dienst, um auf Google Drive zuzugreifen
    drive_service = getDriveService()

    #Suche nach ID
    ret, id = searchID(drive_service, mimetype, data)
    if not ret:
        return False, None

    #Suchen Sie nach Wettervorhersagebildern
    request = drive_service.files().get_media(fileId=id)
    fh = io.BytesIO()
    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while done is False:
        status, done = downloader.next_chunk()
    
    return True, fh.getvalue()


def devideImage_M5stack(imgBinary, _trim):
    """Teilen Sie das Bild für M5Stack. Der Rückgabewert sind Bilddaten
    """
    imgNumpy = 0x00

    #Bestätigung der Eingabedaten
    if _trim.isnumeric():
        trimPos = int(_trim)
        if trimPos <= 0 or trimPos > 8:
            return False
    else:
        return False

    #Bildaufteilung
    # 1 2 3 4
    # 5 6 7 8
    Trim = [
        (0, 0, 80, 120),
        (80, 0, 160, 120),
        (160, 0, 240, 120),
        (240, 0, 320, 120),
        (0, 120, 80, 240),
        (80, 120, 160, 240),
        (160, 120, 240, 240),
        (240, 120, 320, 240),
    ]

    #PIL-Bild<-Binärdaten
    img_pil = Image.open(BytesIO(imgBinary))

    #Trimmen
    im_crop = img_pil.crop(Trim[trimPos - 1])

    #numpy Array(RGBA) <-PIL-Bild
    imgNumpy = np.asarray(im_crop)

    return True, imgNumpy


def getBinary(img):
    """Konvertieren Sie Bilder in Binärdaten
    """
    ret = ""
    pilImg = Image.fromarray(np.uint8(img))
    output = io.BytesIO()
    pilImg.save(output, format="JPEG")
    ret = output.getvalue()

    return ret


def getDriveImg_Binary(imgName, trim):
    """Holen Sie sich das Bild in googleDrive gespeichert. Der Rückgabewert sind Binärdaten.
    """

    img = 0x00

    #Bild vom Laufwerk(Binärdaten)Erhalten
    ret, imgBinary = downloadData("image/jpeg", imgName)
    if not ret:
        print("...error")
        return ""

    print(ret, len(imgBinary))

    #Teilen Sie das Bild
    #* Nur für M5-Stapel
    if trim is not None:
        isGet, img = devideImage_M5stack(imgBinary, trim)
        if not isGet:
            return ""

        #In Binärdaten konvertieren
        imgBinary = getBinary(img)

    return imgBinary


def getDriveImage_M5stack(request):
    imgName = ""
    trim = "0"

    #Daten anfordern(JSON)Konvertieren
    request_json = request.get_json()

    #Erhalten Sie Zugriffsinformationen zu Google Drive
    if request_json and "drive" in request_json:
        imgName = request_json["drive"]["img"]
        trim = request_json["drive"]["trim"]
    else:
        return ""

    #Holen Sie sich ein getrimmtes Wettervorhersagebild
    ret = getDriveImg_Binary(imgName, trim)

    return ret

Anwendung

Das Gute an diesem Mechanismus ist, dass "** Sie können es auf M5Stack anzeigen, wenn Sie ein Bild vorbereiten **". Mit anderen Worten, es ist nicht auf Wettervorhersagen beschränkt, sondern kann alles wie Zeitpläne und Aufgaben verarbeiten. Legen Sie auf der M5Stack-Seite einfach den zu erfassenden Bildnamen fest. Da das Bild außerhalb von M5Stack generiert wird, müssen Sie das M5Stack-Programm nicht berühren, wenn Sie das Bild ändern möchten.

Das folgende Muster zeigt den Google-Kalender an. (Der Zeitplan ist Mosaik) CalenderImg.png

Zusammenfassung

Durch die Erstellung eines Bildanzeigesystems, das diesmal zu M5Stack passt, habe ich mir einige Anwendungsmuster überlegt. Das Display von M5Stack hat genau die richtige Größe für den Tisch, daher möchte ich es auf verschiedene Arten verwenden.

Ich hoffe es wird für Sie hilfreich sein. Bis bald.

Referenz

[Hochladen von Daten von NefryBT auf Google Drive](https://dotstud.io/blog/update-nefrybt-to-googledrive/#%E3%82%A2%E3%83%83%E3%83%97% E3% 83% AD% E3% 83% BC% E3% 83% 89% E3% 81% BE% E3% 81% A7% E3% 81% AE% E6% 89% 8B% E9% A0% 86 ) Python-Aktualisierungstoken Google API: Verwenden Sie oauth2client.client, um Anmeldeinformationen vom Aktualisierungstoken abzurufen Anfrage über HTTP-Kommunikation senden

Recommended Posts

Anzeigen von Wettervorhersagen auf M5Stack + Google Cloud Platform
Versuchen Sie, Distributed TensorFlow auf der Google Cloud Platform auszuführen
Erstellen Sie eine Ubuntu-Python-Entwicklungsumgebung auf der Google Cloud Platform
Zeigen Sie die mit Rails gem'geocoder 'eingegebene Adresse in Google Map an
Lassen Sie uns die Super Resolution API mithilfe der Google Cloud Platform veröffentlichen
Starten Sie Data Science in der Cloud
[Android] Zeigen Sie Bilder im Web im infoWindow von Google Map an
Tweet die Wettervorhersage mit Bot
Verwenden Sie den Metabolic Disassembler in Google Colaboratory
Zeigen Sie das Diagramm von tensorBoard auf jupyter an
Zeigen Sie ImageField-Bilder normalerweise mit Django + Google Cloud Strage auf dem Server an
Fordern Sie die Herausforderungen von Cyma weiterhin mit dem OCR-Dienst der Google Cloud Platform heraus
Tweet die Wettervorhersage mit Bot Teil 2
Zeigen Sie den QR-Code schnell in der Befehlszeile an
Ich habe versucht, die Google Cloud Vision-API zu verwenden
Verwendung der Google Cloud Translation API
[GoogleCloudPlatform] Verwenden Sie die Google Cloud-API mit der API-Clientbibliothek