最近知りました。
これで、Busterへのupgradeが楽になった。
The examples below show a /boot partition smaller than recommended for the recent Rasbian Buster release.
rpi-clone version 2.0.21 adds the -p option so the /boot partition can be resized at the same time
the root partition is resized to the end of the disk.
If you upgraded Stretch to Buster and are running with a small /boot,
then for the clone to have a resized /boot, run:
$ rpi-clone -f -p 256M sda
2020年3月31日火曜日
2020年3月26日木曜日
Show weather reports Controlling MAX7219 8x8 Matrix LED with Raspberry Pi
MAX7219 制御の8x8 Matrix LEDに天気情報を流すPython scriptです。
[MAX7219_matrix_weather3.py]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import argparse
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
import local_weather
import img_gen2
def text_get():
text=local_weather.get_weather()
return text
def main(n, block_orientation, rotate, inreverse):
# create matrix device
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=n or 1, block_orientation=block_orientation,
rotate=rotate or 0, blocks_arranged_in_reverse_order=inreverse)
text=text_get()
image_list = img_gen2.text_img_gen(n, text)
max_images = len(image_list)
while True:
for i in range(0, max_images):
device.display(image_list[i].convert(device.mode))
time.sleep(0.1)
# time.sleep(0.5)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='matrix_demo arguments',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--cascaded', '-n', type=int, default=4, help='Number of cascaded MAX7219 LED matrices')
# parser.add_argument('--block-orientation', type=int, default=0, choices=[0, 90, -90], help='Corrects block orientation when wired vertically')
parser.add_argument('--block-orientation', type=int, default=-90, choices=[0, 90, -90], help='Corrects block orientation when wired vertically')
# parser.add_argument('--rotate', type=int, default=0, choices=[0, 1, 2, 3], help='Rotate display 0=0°, 1=90°, 2=180°, 3=270°')
parser.add_argument('--rotate', type=int, default=2, choices=[0, 1, 2, 3], help='Rotate display 0=0°, 1=90°, 2=180°, 3=270°')
parser.add_argument('--reverse-order', type=bool, default=False, help='Set to true if blocks are in reverse order')
args = parser.parse_args()
try:
main(args.cascaded, args.block_orientation, args.rotate, args.reverse_order)
except KeyboardInterrupt:
pass
[img_gen2.py]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
_WIDTH=8
def text_img_gen(n, text):
text_len=len(text)
image = Image.new('1', (text_len*8, 8))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("/home/pi/font/misakifont/misaki_gothic.ttf", 8, encoding='unic')
draw.text((0,0), text, font=font, fill=255)
image_list = horizontal_scroll(n, image)
return image_list
def horizontal_scroll(n, image, padding=True):
image_list = list()
width = image.size[0]
w, hight = image.size
# Scroll into the blank image.
if padding:
for x in range(n*_WIDTH):
section = image.crop((0, 0, x, hight))
display_section = create_blank_image(n, hight)
display_section.paste(section, (_WIDTH*n - x, 0, _WIDTH*n, hight))
image_list.append(display_section)
#Scroll across the input image.
for x in range(8*n, width + 1):
section = image.crop((x - _WIDTH*n, 0, x, hight))
display_section = create_blank_image(n, hight)
display_section.paste(section, (0, 0, _WIDTH*n, hight))
image_list.append(display_section)
#Scroll out, leaving the blank image.
if padding:
for x in range(width - (_WIDTH*n-1), width + 1):
section = image.crop((x, 0, width, hight))
display_section = create_blank_image(n, hight)
display_section.paste(section, (0, 0, ((_WIDTH*n)-1) - (x - (width - ((_WIDTH*n)-1))), hight))
image_list.append(display_section)
#Return the list of images created
return image_list
def create_blank_image(n, hight):
return Image.new("RGB", (_WIDTH*n, hight))
[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'
[MAX7219_matrix_weather3.py]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import argparse
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
import local_weather
import img_gen2
def text_get():
text=local_weather.get_weather()
return text
def main(n, block_orientation, rotate, inreverse):
# create matrix device
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=n or 1, block_orientation=block_orientation,
rotate=rotate or 0, blocks_arranged_in_reverse_order=inreverse)
text=text_get()
image_list = img_gen2.text_img_gen(n, text)
max_images = len(image_list)
while True:
for i in range(0, max_images):
device.display(image_list[i].convert(device.mode))
time.sleep(0.1)
# time.sleep(0.5)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='matrix_demo arguments',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--cascaded', '-n', type=int, default=4, help='Number of cascaded MAX7219 LED matrices')
# parser.add_argument('--block-orientation', type=int, default=0, choices=[0, 90, -90], help='Corrects block orientation when wired vertically')
parser.add_argument('--block-orientation', type=int, default=-90, choices=[0, 90, -90], help='Corrects block orientation when wired vertically')
# parser.add_argument('--rotate', type=int, default=0, choices=[0, 1, 2, 3], help='Rotate display 0=0°, 1=90°, 2=180°, 3=270°')
parser.add_argument('--rotate', type=int, default=2, choices=[0, 1, 2, 3], help='Rotate display 0=0°, 1=90°, 2=180°, 3=270°')
parser.add_argument('--reverse-order', type=bool, default=False, help='Set to true if blocks are in reverse order')
args = parser.parse_args()
try:
main(args.cascaded, args.block_orientation, args.rotate, args.reverse_order)
except KeyboardInterrupt:
pass
[img_gen2.py]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
_WIDTH=8
def text_img_gen(n, text):
text_len=len(text)
image = Image.new('1', (text_len*8, 8))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("/home/pi/font/misakifont/misaki_gothic.ttf", 8, encoding='unic')
draw.text((0,0), text, font=font, fill=255)
image_list = horizontal_scroll(n, image)
return image_list
def horizontal_scroll(n, image, padding=True):
image_list = list()
width = image.size[0]
w, hight = image.size
# Scroll into the blank image.
if padding:
for x in range(n*_WIDTH):
section = image.crop((0, 0, x, hight))
display_section = create_blank_image(n, hight)
display_section.paste(section, (_WIDTH*n - x, 0, _WIDTH*n, hight))
image_list.append(display_section)
#Scroll across the input image.
for x in range(8*n, width + 1):
section = image.crop((x - _WIDTH*n, 0, x, hight))
display_section = create_blank_image(n, hight)
display_section.paste(section, (0, 0, _WIDTH*n, hight))
image_list.append(display_section)
#Scroll out, leaving the blank image.
if padding:
for x in range(width - (_WIDTH*n-1), width + 1):
section = image.crop((x, 0, width, hight))
display_section = create_blank_image(n, hight)
display_section.paste(section, (0, 0, ((_WIDTH*n)-1) - (x - (width - ((_WIDTH*n)-1))), hight))
image_list.append(display_section)
#Return the list of images created
return image_list
def create_blank_image(n, hight):
return Image.new("RGB", (_WIDTH*n, hight))
[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' ### 2021/2/21 update
# 東京の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)
# 東京の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)
登録:
投稿 (Atom)