2024年10月28日月曜日

Show weather reports OLED(SSD1306) with Raspberry Pi

Raspberry Pi Zero W Rev 1.1にinstallしたRaspberry pi OS 12 (bookworm) の動作確認です

OLED(SSD1306)に天気情報を流すPython scriptを書いてみた。


ベースのコードは、Adafruit_CircuitPython_SSD1306 の/examples/ssd1306_pillow_animate.py

# pip install adafruit-circuitpython-ssd1306
# pip install pillow
# git clone https://github.com/adafruit/Adafruit_CircuitPython_SSD1306

fontは、IPAフォントを使用
#apt install fonts-ipaexfont

[p3-ssd1306_pillow_animate_weather-flat-24.py]

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

# SPDX-FileCopyrightText: 2014 Tony DiCola for Adafruit Industries
# SPDX-License-Identifier: MIT

# This example is for use on (Linux) computers that are using CPython with
# Adafruit Blinka to support CircuitPython libraries. CircuitPython does
# not support PIL/pillow (python imaging library)!

import math
import time
from board import SCL, SDA
import busio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306

#####
import local_weather

def text_get():

   text=local_weather.get_weather()
   return text


#####
text=text_get()

font = ImageFont.truetype("fonts-japanese-gothic.ttf", 24)

# Create the I2C interface.
i2c = busio.I2C(SCL, SDA)

# Create the SSD1306 OLED class.
# The first two parameters are the pixel width and pixel height.
# Change these to the right size for your display!
disp = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)

# Note you can change the I2C address, or add a reset pin:
# disp = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, addr=0x3c, reset=reset_pin)

# Get display width and height.
width = disp.width
height = disp.height

# Clear display.
disp.fill(0)
disp.show()

# Create image buffer.
# Make sure to create image with mode '1' for 1-bit color.
image = Image.new("1", (width, height))

# Load default font.
###org## font = ImageFont.load_default()

# Alternatively load a TTF font.  Make sure the .ttf font file is in the
# same directory as this python script!
# Some nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)

# Create drawing object.
draw = ImageDraw.Draw(image)

# Define text and get total width.
##text = (
##    "SSD1306 ORGANIC LED DISPLAY. THIS IS AN OLD SCHOOL DEMO SCROLLER!!"
##    + "GREETZ TO: LADYADA & THE ADAFRUIT CREW, TRIXTER, FUTURE CREW, AND FARBRAUSCH"
##)
bbox = draw.textbbox((0, 0), text, font=font)
maxwidth = bbox[2] - bbox[0]

# Set animation and sine wave parameters.
amplitude = height / 4
offset = height / 2 - 4
velocity = -2
startpos = width

# Animate text moving in sine wave.
print("Press Ctrl-C to quit.")
pos = startpos
while True:
    # Clear image buffer by drawing a black filled box.
    draw.rectangle((0, 0, width, height), outline=0, fill=0)
    # Enumerate characters and draw them offset vertically based on a sine wave.
    x = pos
    for i, c in enumerate(text):
        # Stop drawing if off the right side of screen.
        if x > width:
            break
        # Calculate width but skip drawing if off the left side of screen.
        if x < -10:
            bbox = draw.textbbox((0, 0), c, font=font)
            char_width, char_height = bbox[2] - bbox[0], bbox[3] - bbox[1]
            x += char_width
            continue
        # Calculate offset from sine wave.
##org        y = offset + math.floor(amplitude * math.sin(x / float(width) * 2.0 * math.pi))
        # Draw text.
##        draw.text((x, y), c, font=font, fill=255)
##      append by pi 2924/9  flat!! fstart
        y=0
##      append by pi 2924/9  end
        draw.text((x, y), c, font=font, fill=255)
        # Increment x position based on chacacter width.
        bbox = draw.textbbox((0, 0), c, font=font)
        char_width, char_height = bbox[2] - bbox[0], bbox[3] - bbox[1]
        x += char_width

    # Draw the image buffer.
    disp.image(image)
    disp.show()

    # Move position for next frame.
    pos += velocity
    # Start over if text has scrolled completely off left side of screen.
    if pos < -maxwidth:
        pos = startpos

    # Pause briefly before drawing next frame.
####    time.sleep(0.001)

[local_weather.py]

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import json
import requests

#import sys
#sys.dont_write_bytecode = True

def get_weather():
#  url = 'http://weather.livedoor.com/forecast/webservice/json/v1'
  url = 'https://weather.tsukumijima.net/api/forecast'
  # 東京のcityタグのid
  payload = {'city': '130010'}
  # お天気情報をjsonで取得
  try:
     data = requests.get(url, params = payload).json()
  except Exception as e:
#     return e
     return '天気情報がありません'


  # 天気情報をedit
  rt=''
  max_len=len(data['forecasts'])
# 今日、明日、(明後日)の情報
  for forecast in data['forecasts']:
     rt+=('{0} ({1}) '.format(forecast['date'], forecast['dateLabel']))
     rt+=(' {} '.format(forecast['telop']))
     if forecast['temperature'].get('max') is not None:
        rt+= ('最高気温 {}℃  '.format(forecast['temperature']['max']['celsius']))
        rt+= ('最高湿度 {}% '.format(forecast['temperature']['max']['fahrenheit']))
     if forecast['temperature'].get('min') is not None:
        rt+= (' 最低気温 {}℃  '.format(forecast['temperature']['min']['celsius']))
        rt+= (' 最低湿度 {}% '.format(forecast['temperature']['min']['fahrenheit']))
     rt += ('{}の天気は、{}でしょう '.format(forecast['dateLabel'], forecast['telop']))

  rt+=('以降が{}の天気概況 '.format(data['location']['city']))
  rt+=(' ' + data['description']['text'])
  rt=re.sub(r'\n|。|、', "", rt)
  return rt

if __name__ == '__main__':
   rt=get_weather()
   print(rt)