1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラズパイ5 2023年10月更新 bookworm ③ pipが使えない! pythonでグラフィック・ディスプレイを利用

Last updated at Posted at 2024-02-18

 ラズパイ4を用いた<ラズパイ 2023年10月更新 bookworm 連載記事>をラズパイ5で再検証した記事です。

長いです。
元の記事では、bookwormになって、pipの扱いが厳密になり、今回利用しているグラフィック・ディスプレイのように、野良アプリ?がインストールできなくなったので、仮想記憶環境で利用できるようにする話。
ラズパイ4では、上記の話だけだったのですが、ラズパイ5で、新しいチップセットになった際、10年使われてきたRPi.GPIO、wiringPI、pigpioがサポートされていないという状況を打破する話です。仮想記憶環境では、うまく解決しなくて途中であきらめています。
 おすすめではない?、システム側のpython環境に強制的にパッケージをインストールする機能を利用して解決しました。

Adafruit 2.0" 320x240 Color IPS TFT Displayを利用する

Adafruitで入手したSPIバス接続のディスプレイをラズパイにつなぎます。

  2.0" 320x240 Color IPS TFT Display with microSD Card Breakout

名称未設定2-3a88cdf4.png

 2.0インチ、320×240ピクセルのカラーTFTディスプレイで、商品名にコントローラST7789が含まれていませんが、シルクには印刷されています。裏面にメモリ・カードのソケットがついています(今回は使わない)。

 電源およびロジック電圧は3~5Vです。

 このグラフィック・ディスプレイは、SPI接続です。コントローラのST7789にはデバイス・ドライバ(/boot/overlaysのREADME参照)がありますが、表示領域が固定でこのディスプレイの1/4ほどしかなく、画面全体を利用できるpythonで利用できるライブラリを探しました。

 Adafruitラズパイ関連のpython関係のドライバなどは、相当昔に開発をやめ、CircuitPythonのサブシステム(?)上に構築するように変化しています。

 Pimoroni のST7789ライブラリが見つかりました(中身はAdafruit製?)。

  https://github.com/pimoroni/st7789-python/tree/master

 そこに書かれているインストール方法、

  sudo pip3 install st7789

ではなく、次のようにインストールしました。bookwormではPython2はなくなっています。

$ pip install st7789

 しかし、

This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.

If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.

For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.

というメッセージが出ます。

 最初に書かれている解決方法を試します。

$ sudo apt-get install python3-st7789

を実行すると、

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package python3-st7789

が表示されて、apt-getを最新にしても解決しません。つまり、Debianパッケージにはなっていない?ということのようです。

pythonの仮想環境

 次のメッセージを翻訳します。

「Debian パッケージ以外の Python パッケージをインストールする場合は、 python3 -m venv パスを使用して仮想環境を作成します。次に、 path/to/venv/bin/python と path/to/venv/bin/pip を使用します。」

$ python -V

Python 3.11.2

 現在、Python 3.11.2バージョンです。python3の初期のころから仮想環境は利用できるようになっていたようですが、venvが標準的な仮想環境構築に使われるようになったのはバージョン3.3以降からのようです。

 1年ほど前まで、ラズパイでpythonの仮想環境のことを意識することはありませんでした。

 venvは仮想環境を提供する機能で、各仮想環境には、それぞれ異なる種類のパッケージ、異なるバージョンのものをインストールできるそうです。しかし、その必要性を感じない。。。いつも最新の状態に保つという使い方をしていたから。。。

 調べると、仮想環境を利用するには、

  • 作成
  • 有効化

の二つの作業が必要です。

 何と面倒なと思いました。さらに調べると、ラズパイのbookworm は、元となったDebianの2023年6月10日をベースとしています。

 世の中、数年もしくは10年以下で、いろいろなアプリケーションが収束してしまいます。でも、それらを利用したシステムは10年以上メインテナンスをしないといけないことも多いです。したがって、装置一つに、システム丸ごと異なる2バージョンが共存するという事態が起こり、それが実現可能な時代になっています。

 bookwormでは、Python 2.xが完全になくなったことと、Python3はPEP 668に従い、pipでのパッケージ・インストールを拒否することになりました。青天の霹靂です。これが、最初の長いメッセージだったわけです。

 たぶん、bookwormで、

  • Debianディストリビューションそのもの
  • Debian Free Software Guidelines(DFSG)に準拠しているがビルド時もしくは動作時にDebianディストリビューション外のソフトウェアが必要となるもの
  • Debianディストリビューションと互換性はあるがDFSGに準拠しない

が明確に分けられましたが、それがpythonのpipを用いたインストールに影響が出たのではないかと推測。。。いろいろ混在することでトラブルが増え、問題が起こったときの解明に時間を要するというのを避けたいのかもしれません。すごく健全な方向です。

なぜか解決方法が三つある?

 検索すると、大きく三つの解決方法があるようです。

  • --break-system-packagesオプションを利用<その1
  • 手順を踏んで標準搭載のvenvを利用<その2
  • pipxを利用<その3

接続

 SPIバスのインターフェースで、ラズパイとTFTディスプレイとを接続します。

TFTディスプレイ ピン番号GPIOx ピン番号 GPIOx TFTディスプレイ
D/C 15 GPIO22 -
Vin 17 +3.3V -
MOSI 19 GPIO10 MOSI 20 GND GND
- 21 GPIO9 MISO 22 GPIO25 RST
SCK 23 GPIO11 CLK 24 GPIO8 CE0 LCD CS
- 25 GPIO7 CE1 -

 正統派だと思われる2番目の方法から試します。

仮想環境を作り、st7789をインストールする<その2>

 仮想環境を「作成」します。

$ python -m venv env

 3,4(ラズパイ4では7,8)秒ほど時間がたってプロンプトが戻ってきました。lsを実行すると、envというディレクトリができています。

$ cd env
$ ls
bin  include  lib  lib64  pyvenv.cfg

 いくつかのディレクトリやファイルが入っています。

 「有効化」します。

yoshi@raspberrypi:~ $ source env/bin/activate
(env) yoshi@raspberrypi:~ $

 有効化されました。プロンプトが変化して明確に仮想環境に入っていることがわかります。

(env) yoshi@raspberrypi:~ $ pip list
Package    Version
---------- -------
pip        23.0.1
setuptools 66.1.1

 まっさらな状態ですね。st7789ライブラリをこの仮想環境でpipを使ってインストールします。

(env) yoshi@raspberrypi:~ $ pip install st7789
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting st7789
  Using cached https://www.piwheels.org/simple/st7789/ST7789-0.0.4-py3-none-any.whl (8.4 kB)
Installing collected packages: st7789
Successfully installed st7789-0.0.4

(env) yoshi@raspberrypi:~ $ pip list
Package    Version
---------- -------
pip        23.0.1
setuptools 66.1.1
ST7789     0.0.4

 ST7789という名称でインストールされました。以下、ST7789を動かすうえで必要なライブラリを追加でインストールしていきます。

 画像処理のPILライブラリが必要なのでインストールします。

(env) yoshi@raspberrypi:~ $ pip install pillow
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pillow
  Downloading pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl (4.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.3/4.3 MB 10.7 MB/s eta 0:00:00
Installing collected packages: pillow
Successfully installed pillow-10.2.0

 数値演算のnumpyが必要なので、インストールします。

(env) yoshi@raspberrypi:~ $ pip install numpy
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting numpy
  Downloading numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (14.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.2/14.2 MB 35.1 MB/s eta 0:00:00
Installing collected packages: numpy
Successfully installed numpy-1.26.4

 SPIのライブラリspidevが必要なのでインストールします。

(env) yoshi@raspberrypi:~ $ pip install spidev
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting spidev
  Downloading spidev-3.6.tar.gz (11 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Installing backend dependencies ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: spidev
  Building wheel for spidev (pyproject.toml) ... done
  Created wheel for spidev: filename=spidev-3.6-cp311-cp311-linux_aarch64.whl size=42573 sha256=5c930da749437f6e120d68406a433c394f5e8b40dff515586fb463a48a3bc5f1
  Stored in directory: /home/yoshi/.cache/pip/wheels/44/f9/7b/01bb1f281eedaaa562943e27c78dee683ee6e7f3bf2f437101
Successfully built spidev
Installing collected packages: spidev
Successfully installed spidev-3.6

 GPIOのアクセスするRPi.GPIOライブラリが必要なのでインストールします。

(env) yoshi@raspberrypi:~ $ pip install RPi.GPIO
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting RPi.GPIO
  Downloading RPi.GPIO-0.7.1.tar.gz (29 kB)
  Preparing metadata (setup.py) ... done
Installing collected packages: RPi.GPIO
  DEPRECATION: RPi.GPIO is being installed using the legacy 'setup.py install' method, because it does not have a 'pyproject.toml' and the 'wheel' package is not installed. pip 23.1 will enforce this behaviour change. A possible replacement is to enable the '--use-pep517' option. Discussion can be found at https://github.com/pypa/pip/issues/8559
  Running setup.py install for RPi.GPIO ... done
Successfully installed RPi.GPIO-0.7.1

 インストールしたライブラリを表示します。

(env) yoshi@raspberrypi:~ $ pip list
Package    Version
---------- -------
numpy      1.26.3
pillow     10.2.0
pip        23.0.1
RPi.GPIO   0.7.1
setuptools 66.1.1
spidev     3.6
ST7789     0.0.4

 テスト・プログラムを動かします。

  • portはこのSPI接続ブロックを指します。'0'です。
  • csはChip Selectで、CE0もしくはCE1が利用でき、'0'もしくは'1'を設定します。ここではCE0を接続しています。
  • dcはD/C信号で、GPIO22を接続しています。
  • rstはRSTのリセット信号で、GPIO25を接続しています。
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import ST7789

MESSAGE = "Hello World!"
print(MESSAGE)

#display_type == "dhmini":
disp = ST7789.ST7789(
    height=240,
    width=320,
    rotation=0,
    port=0,
    cs=0,
    dc=22,
    rst=25,
    backlight=None,
    spi_speed_hz=80 * 1000 * 1000,
)


# Initialize display.
disp.begin()

WIDTH = disp.width
HEIGHT = disp.height
img = Image.new('RGB', (WIDTH, HEIGHT), color=(255, 0, 0))

draw = ImageDraw.Draw(img)

font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 30)

draw.text((20,20),MESSAGE, font=font, fill=(255,255,255))

disp.display(img)

 実行すると、エラーが出ます。ラズパイ4では動いていました。

(env) yoshi@ras05:~ $ python lcd_1.py
Hello World!
Traceback (most recent call last):
File "/home/yoshi/lcd_1.py", line 11, in
disp = ST7789.ST7789(
^^^^^^^^^^^^^^
File "/home/yoshi/env/lib/python3.11/site-packages/ST7789/init.py", line 139, in init
GPIO.setup(dc, GPIO.OUT)
RuntimeError: Cannot determine SOC peripheral base address

「Cannot determine SOC peripheral base address」は、訳すと「SOC ペリフェラル ベース アドレスを決定できません」ですが、調べると、ラズパイ5ではGPIOをアクセスするライブラリのRPi.GPIOが対応していなく、gapiozeroでは使えるらしいとのことです。

  参考になる質問スレッドRaspberry 5 issue that did not exist with Raspberry 4

 上記のサイトの回答に従い、既存のライブラリを削除し、代替ライブラリをインストールします。

(env) yoshi@ras05:~ $ sudo apt-get remove python3-rpi.gpio
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package 'python3-rpi.gpio' is not installed, so not removed
The following packages were automatically installed and are no longer required:
 rpi.gpio-common rtimucli
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
(env) yoshi@ras05:~ $ pip install rpi-lgpio
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting rpi-lgpio
 Using cached https://www.piwheels.org/simple/rpi-lgpio/rpi_lgpio-0.4-py3-none-any.whl (11 kB)
Installing collected packages: rpi-lgpio
Successfully installed rpi-lgpio-0.4

 削除は失敗していますね。
 プログラムを実行すると、

(env) yoshi@ras05:~ $ python lcd_1.py
Traceback (most recent call last):
  File "/home/yoshi/lcd_1.py", line 5, in <module>
    import ST7789
  File "/home/yoshi/env/lib/python3.11/site-packages/ST7789/__init__.py", line 26, in <module>
    import RPi.GPIO as GPIO
  File "/home/yoshi/env/lib/python3.11/site-packages/RPi/GPIO/__init__.py", line 13, in <module>
    import lgpio
ModuleNotFoundError: No module named 'lgpio'

動きません。

~ $ pip uninstall rpi-lgpio
Found existing installation: rpi-lgpio 0.4
Uninstalling rpi-lgpio-0.4:
  Would remove:
    /home/yoshi/env/lib/python3.11/site-packages/RPi/*
    /home/yoshi/env/lib/python3.11/site-packages/rpi_lgpio-0.4.dist-info/*
  Would not remove (might be manually added):
    /home/yoshi/env/lib/python3.11/site-packages/RPi/_GPIO.cpython-311-aarch64-linux-gnu.so
Proceed (Y/n)? Y
  Successfully uninstalled rpi-lgpio-0.4
(env) yoshi@ras05:~ $ sudo apt-get install python3-rpi.gpio
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following package was automatically installed and is no longer required:
  rtimucli
Use 'sudo apt autoremove' to remove it.
The following NEW packages will be installed:
  python3-rpi.gpio
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 22.0 kB of archives.
After this operation, 96.3 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bookworm/main arm64 python3-rpi.gpio arm64 0.7.1~a4-1+b4 [22.0 kB]
Fetched 22.0 kB in 0s (310 kB/s)
Selecting previously unselected package python3-rpi.gpio.
(Reading database ... 239630 files and directories currently installed.)
Preparing to unpack .../python3-rpi.gpio_0.7.1~a4-1+b4_arm64.deb ...
Unpacking python3-rpi.gpio (0.7.1~a4-1+b4) ...
Setting up python3-rpi.gpio (0.7.1~a4-1+b4) ...
(env) yoshi@ras05:~ $ pip list
Package    Version
---------- -------
numpy      1.26.4
pillow     10.2.0
pip        23.0.1
RPi.GPIO   0.7.1
setuptools 66.1.1
spidev     3.6
ST7789     0.0.4
(env) yoshi@ras05:~ $ python lcd_1.py
Traceback (most recent call last):
  File "/home/yoshi/lcd_1.py", line 5, in <module>
    import ST7789
  File "/home/yoshi/env/lib/python3.11/site-packages/ST7789/__init__.py", line 26, in <module>
    import RPi.GPIO as GPIO
ModuleNotFoundError: No module named 'RPi.GPIO'
(env) yoshi@ras05:~ $ pip install rpi-lgpio
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting rpi-lgpio
  Using cached https://www.piwheels.org/simple/rpi-lgpio/rpi_lgpio-0.4-py3-none-any.whl (11 kB)
Installing collected packages: rpi-lgpio
Successfully installed rpi-lgpio-0.4
(env) yoshi@ras05:~ $ python lcd_1.py
Traceback (most recent call last):
  File "/home/yoshi/lcd_1.py", line 5, in <module>
    import ST7789
  File "/home/yoshi/env/lib/python3.11/site-packages/ST7789/__init__.py", line 26, in <module>
    import RPi.GPIO as GPIO
  File "/home/yoshi/env/lib/python3.11/site-packages/RPi/GPIO/__init__.py", line 13, in <module>
    import lgpio
ModuleNotFoundError: No module named 'lgpio'

 import lgpioしているのに、インストールされたのは、rpi-lgpioのようです。
 pip install lgpio
を実行すると、0.0.0.2という古いのがインストールされ実行時にエラーが出ます。システム側のは、0.2.2.0が入っています。
 というので、解決方法が見つからないので、あきらめました。

 envを抜けます。プロンプトが普通の状態になりました。

(env) yoshi@raspberrypi:~ $ deactivate
yoshi@raspberrypi:~ $

 再度この仮想環境に入るには、<有効化>を実行します。

yoshi@raspberrypi:~ $ source env/bin/activate
(env) yoshi@raspberrypi:~ $

--break-system-packagesオプションを利用<その1>

 つぎに、1番目の簡易的な方法を試します。

$ pip list | grep ST7*

 <その2>のenv仮想環境をぬけているので、ST7789ライブラリは表示されません。

$ pip install --break-system-packages st7789
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting st7789
  Downloading https://www.piwheels.org/simple/st7789/ST7789-0.0.4-py3-none-any.whl (8.4 kB)
Installing collected packages: st7789
Successfully installed st7789-0.0.4

 インストールできました。

$ pip list | grep ST7*
ST7789                             0.0.4

$ pip uninstall --break-system-packages st7789
Found existing installation: ST7789 0.0.4
Uninstalling ST7789-0.0.4:
  Would remove:
    /home/yoshi/.local/lib/python3.11/site-packages/ST7789-0.0.4.dist-info/*
    /home/yoshi/.local/lib/python3.11/site-packages/ST7789/*
Proceed (Y/n)? Y
  Successfully uninstalled ST7789-0.0.4
$ pip list | grep ST7*
$ pip uninstall --break-system-packages st7789

を実行すると、

    /home/yoshi/.local/lib/python3.11/site-packages/ST7789-0.0.4.dist-info/*
    /home/yoshi/.local/lib/python3.11/site-packages/ST7789/*

 .localにインストールされていることがわかります。

 何を確認したかというと、普通のLinuxでは、--userをつけないと、管理者権限で、/userにインストールされるようです。--userをつけてインストールすると、ユーザのホームの中の.localにインストールされるようです。ラズパイのbookworm では、--userをつけなくとも、.localにインストールされていることがわかりました。

 テスト・プログラムを動かします。
 この.local環境では、numpy、pillow、RPi.GPIO、spidev などは、最初から入っているので、インストールは不要です。

 実行しますが、しっかりGPIOのアクセスでエラーが出ます。

yoshi@ras05:~ $ python lcd_1.py
Hello World!
Traceback (most recent call last):
File "/home/yoshi/lcd_1.py", line 11, in <module>
  disp = ST7789.ST7789(
         ^^^^^^^^^^^^^^
File "/home/yoshi/.local/lib/python3.11/site-packages/ST7789/__init__.py", line 139, in __init__
  GPIO.setup(dc, GPIO.OUT)
RuntimeError: Cannot determine SOC peripheral base address

 代替機能をインストールします。

yoshi@ras05:~ $ pip install --break-system-packages rpi-lgpio
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting rpi-lgpio
  Using cached https://www.piwheels.org/simple/rpi-lgpio/rpi_lgpio-0.4-py3-none-any.whl (11 kB)
Installing collected packages: rpi-lgpio
Successfully installed rpi-lgpio-0.4

 実行します。

IMGP2083.png

pipxを利用<その3> <この項目はラズパイ5では実行していません

$ sudo apt-get install pipx
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:

。。。以下、多くのパッケージがインストールされる。

$ pipx install st7789

No apps associated with package st7789 or its dependencies. If you are attempting to install a library, pipx should
not be used. Consider using pip or a similar tool instead.

 どうも使えないようですね。

気圧を表示

 すごく手間がかかりましたが、前回I2Cバスに接続した気圧センサLPS22HBの測定値を、このTFTディスプレイに表示します。

 ディスプレイのライブラリのインストールは一番簡便な<その1>を利用します。

$ pip install --break-system-packages st7789
$ pip install --break-system-packages rpi-lgpio

 プログラムです。

import smbus2
import time
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import ST7789

i2c =  smbus2.SMBus(1)
addr = 0x5d

i2c.write_byte_data(addr, 0x10, 0x10)

disp = ST7789.ST7789(height=240,width=320,rotation=0,
    port=0,cs=0,dc=22,rst=25,backlight=None,
    spi_speed_hz=80 * 1000 * 1000
)

disp.begin()
img = Image.new('RGB', (disp.width, disp.height), color=(32, 32, 32))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf", 40)
draw.text((10,0),'Temp & press', font=font, fill=(255,0,0))
disp.display(img)
time.sleep(2)

while 1:
    i2c.write_byte_data(addr, 0x11, 0x11)
    pdata_XL = i2c.read_byte_data(addr, 0x28)
    pdata_L  = i2c.read_byte_data(addr, 0x29)
    pdata_H  = i2c.read_byte_data(addr, 0x2a)
    press = (pdata_H<<16 | pdata_L << 8 | pdata_XL ) / 4096.0
    Press = str(int(press))
    print("\nPress = " + Press + "hPa")
    tdata_L = i2c.read_byte_data(addr, 0x2b)
    tdata_H = i2c.read_byte_data(addr, 0x2c)
    temp = (tdata_H << 8 | tdata_L ) / 100.0
    Temp = str(round(temp,1))
    print("Temp  = " + Temp + "`C")

    draw.rectangle((20, 50, 200,160), (32,32,32))
    draw.text((20,50),Temp+'`C', font=font, fill=(25,255,25))
    draw.text((20,100),Press+'hPa', font=font, fill=(25,255,25))
    disp.display(img)
    time.sleep(2)

 実行結果です。

IMGP2086.png

電源

 少ない経験なので、汎用的な表現ができません。あくまでも、こういうことがあったという話です。

 ラズパイ3に導入された電源ICでは、GPIO端子の3.3Vがショートしたら、検出してシャットダウンしました。しかし、二度と復帰しませんでした。購入したボードだけかもしれません。
 ラズパイ4では、再度電源を入れたら、電源ICの復帰信号が与えられるようになって、GPIOの3.3V電源ショートから復活しました。
 ラズパイ5では、電源電圧が5.5Vを超えるとリセットがかかり、再起動しなくなりました。
 電源容量の増加に伴って、利用する電源装置によって、立ち上がり時にエラーが出て、起動シーケンスが途中で止まることがありました。ブート媒体はSDメモリではなく、USBメモリからの事例です。config.txtに、usb_max_current_enable=1の記述を追加することで、起動が最後まで進みました。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?