使用したのは、plus のない 無印 Enviro
カスタマイズ後はこんな感じ
1.インストールとカスタマイズの概要
インストールは比較的簡単。pip3 でインストールするやつと apt でインストールするやつがあって、モジュールのインストールする点でちょっと苦労。
インストールには以下のサイトを参照しました。
https://qiita.com/nak435/items/8667ddcd105bf82396e1
https://dalomo.net/blog/2021/11/28/1606/
詳細なデータをリアルタイムで表示するのはすごい。
が、字が小さくて、覗き込まないと時間すらわからない。私にとってちょっと実用できない。
そこで、combined.py ファイルを元に自分用にカスタマイズ。以下の記述はその時の記録だが、コメントしたものといきなり削除したものが混在している。本当は不要なものを削除しスクリプトを短くしたいところだが、どこを不要としたのかの履歴がわからなくなるためやむを得ないと判断。見づらくなっていることは容赦願いたい。
- 表示するのは現在日時と温湿・気圧・光度だけの2グループだけ
- 日本語化
- それをおおよそ10秒間隔で切り替えて表示することにして、1画面の表示はできるだけ字を大きくする
2.まずは日本語化の準備
$ sudo apt update && sudo apt install fonts-ipaexfont -y # IPA フォントのインストール
$ ls -al /usr/share/fonts/truetype # 確認
total 8
drwxr-xr-x 2 root root 4096 Apr 17 08:37 .
drwxr-xr-x 4 root root 4096 Apr 17 08:37 ..
lrwxrwxrwx 1 root root 43 Apr 17 08:37 fonts-japanese-gothic.ttf -> /etc/alternatives/fonts-japanese-gothic.ttf
lrwxrwxrwx 1 root root 43 Apr 17 08:37 fonts-japanese-mincho.ttf -> /etc/alternatives/fonts-japanese-mincho.ttf
3.combined.py ファイルを修正
やるべきことは次の4点。5点目は好みの問題
(1)ロギング関係、空気質関係のモジュール及びスクリプトの削除(またはコメント化)
(2)日付・時間の表示のためのモジュールのインポートとスクリプトの加筆
(3)日本語フォントを使用するよう、スクリプトの修正
(4)モニターから表示がはみ出さないよう、文字の大きさの修正
(5)文字とかバックカラーを好みのカラーに変える。ついでに、これも好みの問題だが、colour を color で統一した。
#!/usr/bin/env python3
import time
import colorsys
import sys
import ST7735
try:
# Transitional fix for breaking change in LTR559
from ltr559 import LTR559
ltr559 = LTR559()
except ImportError:
import ltr559
from bme280 import BME280
#pms5003 空気質測定のためのモジュールで不要
#from enviroplus import gas 空気質測定のためのモジュールで不要
from subprocess import PIPE, Popen
from PIL import Image, ImageDraw,ImageFont
#from fonts.ttf import RobotoMedium as UserFont 日本語フォントを使用するため不要
import datetime # 時間表示関係
from time import sleep, strftime # 時間表示関係
#import logging ロギング関係のため不要
# BME280 temperature/pressure/humidity sensor
bme280 = BME280()
# 以下3行は空気質のための設定で不要
# PMS5003 particulate sensor
# pms5003 = PMS5003()
# time.sleep(1.0)
# Create ST7735 LCD display class
st7735 = ST7735.ST7735(
port=0,
cs=1,
dc=9,
backlight=12,
rotation=270,
spi_speed_hz=10000000
)
# Initialize display
st7735.begin()
WIDTH = st7735.width
HEIGHT = st7735.height
# Set up canvas and font
img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
# 以下2行は日本語ホントを使用するための設定
font_path = '/usr/share/fonts/truetyple/fonts-japanese-gothic.ttf'
UserFont=font_path
font_size_small = 10
font_size_large = 19 # 20 => 19 文字縮小のため
font_size_big = 26 # 時間表示のための追加
font = ImageFont.truetype(UserFont, font_size_large)
smallfont = ImageFont.truetype(UserFont, font_size_small)
bigfont = ImageFont.truetype(UserFont, font_size_big) # 時間表示のためのフォントサイズを指定
back_color = (0,0,0) # white => black 背景を白から黒へ
text_color = (223, 255, 0) # 時間表示のためのフォントカラー追加
x_offset = 2
y_offset = 2
message = ""
# The position of the top bar
top_pos = 25
# Create a values dict to store the data
variables = ["温度, #temperature",
"気圧, #pressure",
"湿度, #humidity",
"光度, #light", ↑ 日本語化 ↓ 以下空気質のため削除
]
units = ["℃",
"hPa",
"%",
"Lux", # ↓ 以下空気質のため削除
]
# Define your own warning limits
# The limits definition follows the order of the variables array
# Example limits explanation for temperature:
# [4,18,28,35] means
# [-273.15 .. 4] -> Dangerously Low
# (4 .. 18] -> Low
# (18 .. 28] -> Normal
# (28 .. 35] -> High
# (35 .. MAX] -> Dangerously High
# DISCLAIMER: The limits provided here are just examples and come
# with NO WARRANTY. The authors of this example code claim
# NO RESPONSIBILITY if reliance on the following values or this
# code in general leads to ANY DAMAGES or DEATH.
limits = [[4, 18, 28, 35],
[250, 650, 1013.25, 1015],
[20, 30, 60, 70],
[-1, -1, 30000, 100000],
[-1, -1, 40, 50],
[-1, -1, 450, 550],
[-1, -1, 200, 300],
[-1, -1, 50, 100],
[-1, -1, 50, 100],
[-1, -1, 50, 100]]
# RGB palette for values on the combined screen
palette = [(0, 0, 255), # Dangerously Low
(0, 255, 255), # Low
(0, 255, 0), # Normal
(255, 255, 0), # High
(255, 0, 0)] # Dangerously High
values = {}
# Displays data and text on the 0.96" LCD
def display_text(variable, data, unit):
# Maintain length of list
values[variable] = values[variable][1:] + [data]
# Scale the values for the variable between 0 and 1
vmin = min(values[variable])
vmax = max(values[variable])
colors = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
# Format the variable name and value
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
# logging.info(message) ロギングのため不要
# draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
# for i in range(len(colors)):
# # Convert the values to colours from red to blue
# colour = (1.0 - colours[i]) * 0.6
# r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
# Draw a 1-pixel wide rectangle of colour
# draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
# Draw a line graph in black
# line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos))) + top_pos
# draw.rectangle((i, line_y, i + 1, line_y + 1), (0, 0, 0))
# Write the text at the top in black
# draw.text((0, 0), message, font=font, fill=(0, 0, 0))
# st7735.display(img)
# Saves the data to be used in the graphs later and prints to the log
def save_data(idx, data):
variable = variables[idx]
# Maintain length of list
values[variable] = values[variable][1:] + [data]
unit = units[idx]
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
# logging.info(message) ロギング関係のため削除
# Displays all the text on the 0.96" LCD
def display_everything():
draw.rectangle((0, 0, WIDTH, HEIGHT), (0, 0, 0))
column_count = 1 # 2 => 1 行表示に変更
row_count = (len(variables) / column_count)
for i in range(len(variables)):
variable = variables[i]
data_value = values[variable][-1]
unit = units[i]
x = x_offset + ((WIDTH // column_count) * (i // row_count))
y = y_offset + ((HEIGHT大きな文字で表示できるようカスタマイズした。 / row_count) * (i % row_count))
message = "{}: {:.1f} {}".format(variable[:2], data_value, unit) # 日本語表示のために 4 => 2 に変更
lim = limits[i]
rgb = palette[0]
for j in range(len(lim)):
if data_value > lim[j]:
rgb = palette[j + 1]文字を大きくして見やすく
draw.text((x, y), message, font=font, fill=rgb) # font = smallfont => font = font
st7735.display(img)
# Get the temperature of the CPU for compensation
def get_cpu_temperature():
process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
output, _error = process.communicate()
return float(output[output.index('=') + 1:output.rindex("'")])
def main():
# Tuning factor for compensation. Decrease this number to adjust the
# temperature down, and increase to adjust up
factor = 2.25
cpu_temps = [get_cpu_temperature()] * 5
delay = 0.5 # Debounce the proximity tap
mode = 10 # The starting mode
last_page = 0
for v in variables:
values[v] = [1] * WIDTH
# The main loop
try:
while True:
while True:
proximity = ltr559.get_proximity()
# If the proximity crosses the threshold, toggle the mode
if proximity > 1500 and time.time() - last_page > delay:
mode += 1
mode %= (len(variables) + 1)
last_page = time.time()
# One mode for each variable
if mode == 0:
# variable = "temperature"
unit = "C"
cpu_temp = get_cpu_temperature()
# Smooth out with some averaging to decrease jitter
cpu_temps = cpu_temps[1:] + [cpu_temp]
avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
raw_temp = bme280.get_temperature()
data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
display_text(variables[mode], data, unit)
if mode == 1:
# variable = "pressure"
unit = "hPa"
data = bme280.get_pressure()
display_text(variables[mode], data, unit)
if mode == 2:
# variable = "humidity"
unit = "%"
data = bme280.get_humidity()
display_text(variables[mode], data, unit)
if mode == 3:
# variable = "light"
unit = "Lux"はは
if proximity < 10:
data = ltr559.get_lux()
else:
data = 1
display_text(variables[mode], data, unit)
# モード 4 以下 9 まで空気室のため削除
if mode == 10:
# Everything on one screen
cpu_temp = get_cpu_temperature()
# Smooth out with some averaging to decrease jitter
cpu_temps = cpu_temps[1:] + [cpu_temp]
avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
raw_temp = bme280.get_temperature()
raw_data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
save_data(0, raw_data)
display_everything()
raw_data = bme280.get_pressure()
save_data(1, raw_data)
display_everything()
raw_data = bme280.get_humidity()
save_data(2, raw_data)
if proximity < 10:
raw_data = ltr559.get_lux()
else:
raw_data = 1
save_data(3, raw_data)
display_everything()
sleep(10) # 10秒間表示
n = 0 # 以下時間表示のために追加
while n < 11:
local_time = datetime.datetime.now()
time_elapsed = time.time()
d_week = {'Sun':'日', 'Mon':'月', 'Tue':'火', 'Wed':'水', 'Thu':'木', 'Fri':'金', 'Sat':'土'}
key = local_time.strftime("%a")
week = d_week[key]
draw.rectangle((0, 0, 160, 80), back_color)
date_string = local_time.strftime("%Y/%m/%d").lstrip('0')
#week_string = local_time.strftime("(%a)")
week_string = '( ' + week + ' )'
time_string = local_time.strftime("%H:%M")
draw.text((2,0) , date_string, font = bigfont, fill = text_color)
draw.text((2,35), week_string, font = bigfont, fill = text_color)
draw.text((80,35), time_string, font = bigfont, fill = text_color)
st7735.display(img)
sleep(0.5)
local_time = datetime.datetime.now()
time_elapsed = time.time()
d_week = {'Sun':'日', 'Mon':'月', 'Tue':'火', 'Wed':'水', 'Thu':'木', 'Fri':'金', 'Sat':'土'}
key = local_time.strftime("%a")
week = d_week[key]
draw.rectangle((0, 0, 160, 80), back_color)
date_string = local_time.strftime("%Y/%m/%d").lstrip('0')
#week_string = local_time.strftime("(%a)")
week_string = '( ' + week + ' )'
time_string = local_time.strftime("%H %M")
draw.text((2,0) , date_string, font = bigfont, fill = text_color)
draw.text((2,35), week_string, font = bigfont, fill = text_color)
draw.text((80,35), time_string, font = bigfont, fill = text_color)
st7735.display(img)
sleep(0.5)
n += 1
# Exit cleanly
except KeyboardInterrupt:
sys.exit(0)
if __name__ == "__main__":
main()
カスタマイズの概要#!/usr/bin/env python3
import time
import colorsys
import sys
import ST7735
try:
# Transitional fix for breaking change in LTR559
from ltr559 import LTR559
ltr559 = LTR559()
except ImportError:
import ltr559
from bme280 import BME280
#pms5003 空気質測定のためのモジュールで不要
#from enviroplus import gas 空気質測定のためのモジュールで不要
from subprocess import PIPE, Popen
from PIL import Image, ImageDraw,ImageFont
#from fonts.ttf import RobotoMedium as UserFont 日本語フォントを使用するため不要
import datetime # 時間表示関係
from time import sleep, strftime # 時間表示関係
#import logging ロギング関係のため不要
# BME280 temperature/pressure/humidity sensor
bme280 = BME280()
# 以下3行は空気質のための設定で不要
# PMS5003 particulate sensor
# pms5003 = PMS5003()
# time.sleep(1.0)
# Create ST7735 LCD display class
st7735 = ST7735.ST7735(
port=0,
cs=1,
dc=9,
backlight=12,
rotation=270,
spi_speed_hz=10000000
)
# Initialize display
st7735.begin()
WIDTH = st7735.width
HEIGHT = st7735.height
# Set up canvas and font
img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
# 以下2行は日本語ホントを使用するための設定
font_path = '/usr/share/fonts/truetyple/fonts-japanese-gothic.ttf'
UserFont=font_path
font_size_small = 10
font_size_large = 19 # 20 => 19 文字縮小のため
font_size_big = 26 # 時間表示のための追加
font = ImageFont.truetype(UserFont, font_size_large)
smallfont = ImageFont.truetype(UserFont, font_size_small)
bigfont = ImageFont.truetype(UserFont, font_size_big) # 時間表示のためのフォントサイズを指定
back_color = (0,0,0) # white => black 背景を白から黒へ
text_color = (223, 255, 0) # 時間表示のためのフォントカラー追加
x_offset = 2
y_offset = 2
message = ""
# The position of the top bar
top_pos = 25
# Create a values dict to store the data
variables = ["温度, #temperature",
"気圧, #pressure",
"湿度, #humidity",
"光度, #light", ↑ 日本語化 ↓ 以下空気質のため削除
]
units = ["℃",
"hPa",
"%",
"Lux", # ↓ 以下空気質のため削除
]
# Define your own warning limits
# The limits definition follows the order of the variables array
# Example limits explanation for temperature:
# [4,18,28,35] means
# [-273.15 .. 4] -> Dangerously Low
# (4 .. 18] -> Low
# (18 .. 28] -> Normal
# (28 .. 35] -> High
# (35 .. MAX] -> Dangerously High
# DISCLAIMER: The limits provided here are just examples and come
# with NO WARRANTY. The authors of this example code claim
# NO RESPONSIBILITY if reliance on the following values or this
# code in general leads to ANY DAMAGES or DEATH.
limits = [[4, 18, 28, 35],
[250, 650, 1013.25, 1015],
[20, 30, 60, 70],
[-1, -1, 30000, 100000],
[-1, -1, 40, 50],
[-1, -1, 450, 550],
[-1, -1, 200, 300],
[-1, -1, 50, 100],
[-1, -1, 50, 100],
[-1, -1, 50, 100]]
# RGB palette for values on the combined screen
palette = [(0, 0, 255), # Dangerously Low
(0, 255, 255), # Low
(0, 255, 0), # Normal
(255, 255, 0), # High
(255, 0, 0)] # Dangerously High
values = {}
# Displays data and text on the 0.96" LCD
def display_text(variable, data, unit):
# Maintain length of list
values[variable] = values[variable][1:] + [data]
# Scale the values for the variable between 0 and 1
vmin = min(values[variable])
vmax = max(values[variable])
colors = [(v - vmin + 1) / (vmax - vmin + 1) for v in values[variable]]
# Format the variable name and value
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
# logging.info(message) ロギングのため不要
# draw.rectangle((0, 0, WIDTH, HEIGHT), (255, 255, 255))
# for i in range(len(colors)):
# # Convert the values to colours from red to blue
# colour = (1.0 - colours[i]) * 0.6
# r, g, b = [int(x * 255.0) for x in colorsys.hsv_to_rgb(colour, 1.0, 1.0)]
# Draw a 1-pixel wide rectangle of colour
# draw.rectangle((i, top_pos, i + 1, HEIGHT), (r, g, b))
# Draw a line graph in black
# line_y = HEIGHT - (top_pos + (colours[i] * (HEIGHT - top_pos))) + top_pos
# draw.rectangle((i, line_y, i + 1, line_y + 1), (0, 0, 0))
# Write the text at the top in black
# draw.text((0, 0), message, font=font, fill=(0, 0, 0))
# st7735.display(img)
# Saves the data to be used in the graphs later and prints to the log
def save_data(idx, data):
variable = variables[idx]
# Maintain length of list
values[variable] = values[variable][1:] + [data]
unit = units[idx]
message = "{}: {:.1f} {}".format(variable[:4], data, unit)
# logging.info(message) ロギング関係のため削除
# Displays all the text on the 0.96" LCD
def display_everything():
draw.rectangle((0, 0, WIDTH, HEIGHT), (0, 0, 0))
column_count = 1 # 2 => 1 行表示に変更
row_count = (len(variables) / column_count)
for i in range(len(variables)):
variable = variables[i]
data_value = values[variable][-1]
unit = units[i]
x = x_offset + ((WIDTH // column_count) * (i // row_count))
y = y_offset + ((HEIGHT大きな文字で表示できるようカスタマイズした。 / row_count) * (i % row_count))
message = "{}: {:.1f} {}".format(variable[:2], data_value, unit) # 日本語表示のために 4 => 2 に変更
lim = limits[i]
rgb = palette[0]
for j in range(len(lim)):
if data_value > lim[j]:
rgb = palette[j + 1]文字を大きくして見やすく
draw.text((x, y), message, font=font, fill=rgb) # font = smallfont => font = font
st7735.display(img)
# Get the temperature of the CPU for compensation
def get_cpu_temperature():
process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE, universal_newlines=True)
output, _error = process.communicate()
return float(output[output.index('=') + 1:output.rindex("'")])
def main():
# Tuning factor for compensation. Decrease this number to adjust the
# temperature down, and increase to adjust up
factor = 2.25
cpu_temps = [get_cpu_temperature()] * 5
delay = 0.5 # Debounce the proximity tap
mode = 10 # The starting mode
last_page = 0
for v in variables:
values[v] = [1] * WIDTH
# The main loop
try:
while True:
while True:
proximity = ltr559.get_proximity()
# If the proximity crosses the threshold, toggle the mode
if proximity > 1500 and time.time() - last_page > delay:
mode += 1
mode %= (len(variables) + 1)
last_page = time.time()
# One mode for each variable
if mode == 0:
# variable = "temperature"
unit = "C"
cpu_temp = get_cpu_temperature()
# Smooth out with some averaging to decrease jitter
cpu_temps = cpu_temps[1:] + [cpu_temp]
avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
raw_temp = bme280.get_temperature()
data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
display_text(variables[mode], data, unit)
if mode == 1:
# variable = "pressure"
unit = "hPa"
data = bme280.get_pressure()
display_text(variables[mode], data, unit)
if mode == 2:
# variable = "humidity"
unit = "%"
data = bme280.get_humidity()
display_text(variables[mode], data, unit)
if mode == 3:
# variable = "light"
unit = "Lux"はは
if proximity < 10:
data = ltr559.get_lux()
else:
data = 1
display_text(variables[mode], data, unit)
# モード 4 以下 9 まで空気室のため削除
if mode == 10:
# Everything on one screen
cpu_temp = get_cpu_temperature()
# Smooth out with some averaging to decrease jitter
cpu_temps = cpu_temps[1:] + [cpu_temp]
avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
raw_temp = bme280.get_temperature()
raw_data = raw_temp - ((avg_cpu_temp - raw_temp) / factor)
save_data(0, raw_data)
display_everything()
raw_data = bme280.get_pressure()
save_data(1, raw_data)
display_everything()
raw_data = bme280.get_humidity()
save_data(2, raw_data)
if proximity < 10:
raw_data = ltr559.get_lux()
else:
raw_data = 1
save_data(3, raw_data)
display_everything()
sleep(10) # 10秒間表示
n = 0 # 以下時間表示のために追加
while n < 11:
local_time = datetime.datetime.now()
time_elapsed = time.time()
d_week = {'Sun':'日', 'Mon':'月', 'Tue':'火', 'Wed':'水', 'Thu':'木', 'Fri':'金', 'Sat':'土'}
key = local_time.strftime("%a")
week = d_week[key]
draw.rectangle((0, 0, 160, 80), back_color)
date_string = local_time.strftime("%Y/%m/%d").lstrip('0')
#week_string = local_time.strftime("(%a)")
week_string = '( ' + week + ' )'
time_string = local_time.strftime("%H:%M")
draw.text((2,0) , date_string, font = bigfont, fill = text_color)
draw.text((2,35), week_string, font = bigfont, fill = text_color)
draw.text((80,35), time_string, font = bigfont, fill = text_color)
st7735.display(img)
sleep(0.5)
local_time = datetime.datetime.now()
time_elapsed = time.time()
d_week = {'Sun':'日', 'Mon':'月', 'Tue':'火', 'Wed':'水', 'Thu':'木', 'Fri':'金', 'Sat':'土'}
key = local_time.strftime("%a")
week = d_week[key]
draw.rectangle((0, 0, 160, 80), back_color)
date_string = local_time.strftime("%Y/%m/%d").lstrip('0')
#week_string = local_time.strftime("(%a)")
week_string = '( ' + week + ' )'
time_string = local_time.strftime("%H %M")
draw.text((2,0) , date_string, font = bigfont, fill = text_color)
draw.text((2,35), week_string, font = bigfont, fill = text_color)
draw.text((80,35), time_string, font = bigfont, fill = text_color)
st7735.display(img)
sleep(0.5)
n += 1
# Exit cleanly
except KeyboardInterrupt:
sys.exit(0)
if __name__ == "__main__":
main()
曜日の日本語化にあたってはこちらを参照しました。
コメント