【Raspberry Pi4】デスクトップなしOSの初期設定とトラブル対応【随時更新】

2024/07/15

ラズパイ

  • B!
サムネ
サムネ

Raspberry Pi4をNAS用途、DiscordBot用に稼働させているが、どんな設定をしたか忘れないために記録する。

環境は以下の通りである。

  1. $ lsb_release -a
  2.  
  3. No LSB modules are available.
  4. Distributor ID: Debian
  5. Description: Debian GNU/Linux 12 (bookworm)
  6. Release: 12
  7. Codename: bookworm

OS書き込み

RaspberryPi ImagerでOSを書き込む前にWi-Fiの設定やパスワード、SSHの有効化を行っておく。

OS書き込み

自動ログインの設定

ラズパイの電源を入れてログインする。

  1. sudo raspi-config
  • STEP1
    System Options
    自動ログイン1
  • STEP2
    Boot / Auto Login Select boot into desktop or command line
    自動ログイン2
  • STEP3
    Console Autologin Text console, automatically logged in as '***' user
    自動ログイン3

再起動して確認する。

コンソールの文字の大きさ

小型のディスプレイを使用している場合は、ディスプレイの文字の大きさが小さくなって見えにくいため、大きさを変更する。

  • STEP1
    System Options
    1. sudo dpkg-reconfigure console-setup
  • STEP2
    UTF-8
    文字の大きさ1
  • STEP3
    Guess optimal character set
    文字の大きさ2
  • STEP4
    Terminus
    文字の大きさ3
  • STEP5
    16x32(見やすい大きさ)
    文字の大きさ4

Wi-Fiパワーマネージメント

初期状態ではONになっており、速度が遅かったり、切断の原因になるためOFFにする。

  1. sudo iwconfig wlan0 power off
  2. sudo nano /etc/rc.local

/etc/rc.local
  1. #この部分を [exit 0] の上に追記
  2. iwconfig wlan0 power off
  3.  
  4. exit 0

rc.localに記述することで再起動してもpower managementをOFFにすることができる。

IPの固定化

ラズパイのネットワークの設定には「NetworkManager」を使用する。

「dhcpcd」も使えるみたいだが、上手くいかなかったのでアンインストールした。

初期状態ではコネクション名が長いため、分かりやすい名前に変更しておく。

Wired connection 1」を「eth0」に変更する場合は以下の通り。

  1. sudo nmcli connection modify 'Wired connection 1' connection.id eth0

有線LAN
  1. sudo nmcli connection modify eth0 ipv4.addresses 固定したいIP/24
  2. sudo nmcli connection modify eth0 ipv4.gateway デフォルトゲートウェイ
  3. sudo nmcli connection modify eth0 ipv4.dns 8.8.8.8,8.8.4.4
  4. sudo nmcli connection modify eth0 ipv4.method manual
  5. sudo nmcli connection up eth0
  6.  
  7. #設定の確認
  8. nmcli -f ipv4 connection show eth0
  9.  
  10. #設定ファイルの場所
  11. sudo nano /etc/NetworkManager/system-connections/'Wired connection 1.nmconnection'

Wi-Fiも固定IPを設定できる。

Wi-Fi
  1. sudo nmcli connection modify preconfigured ipv4.method manual ipv4.addresses 固定したいIP/24 ipv4.gateway デフォルトゲートウェイ ipv4.dns 8.8.8.8,8.8.4.4
  2. sudo nmcli device disconnect wlan0
  3. sudo nmcli device connect wlan0
  4.  
  5. #設定ファイルの場所
  6. sudo nano /etc/NetworkManager/system-connections/preconfigured.nmconnection

しかし、実際にラズパイを運用する上でWi-Fiは遅く、不安定なため、無効化した方が良い。

合わせてBluetoothも使用しないため、完全に無効化しておく。

  1. sudo nano /boot/firmware/config.txt

/boot/firmware/config.txt
  1. #末尾に以下を追記
  2. dtoverlay=disable-bt
  3. dtoverlay=disable-wifi

再起動してWi-Fiが起動していないことを確認する。

  1. #接続状況の確認
  2. nmcli device status
  3. nmcli connection show

ネットワーク速度テスト

速度がどのくらい出るのか調べたいときがあるのでインストールしておく。

  1. sudo apt install speedtest-cli
  2.  
  3. #実行コマンド
  4. speedtest-cli

結果
  1. Retrieving speedtest.net configuration...
  2. Testing from So-net (****)...
  3. Retrieving speedtest.net server list...
  4. Selecting best server based on ping...
  5. Hosted by Macarne LLC (Tokyo) [**** km]: **** ms
  6. Testing download speed................................................................................
  7. Download: 91.23 Mbit/s
  8. Testing upload speed......................................................................................................
  9. Upload: 90.40 Mbit/s

このように簡単に速度テストができるようになる。

SWAPの無効化

Raspberry Pi4では搭載されているメモリが十分な場合、SWAPの出番がないのでOFFにする。

SWAPをOFFにすることでSDカードの寿命を延ばす効果に期待したい。

  1. #SWAPの確認
  2. free -h
  3.  
  4. sudo swapoff --all
  5. sudo systemctl stop dphys-swapfile
  6. sudo systemctl disable dphys-swapfile
  7. systemctl status dphys-swapfile
  8.  
  9. free -h

USBメモリなどのアンマウント

普通にアンマウントしようとすると target is busy となり、できないことが多い。

-l のオプションをつけることで強制的にアンマウントする。

  1. sudo umount -l /dev/sda1 #例

USBドライバの設定(UASの無効化)

  1. lsusb -t
  2.  
  3. => Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
  4. |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=uas, 5000M

UASが悪さをすることがあるようなので、その場合は以下の設定を行う。

  1. lsusb
  2. #IDをメモする
  3. => Bus 002 Device 002: ID ****:**** JMicron Technology Corp. / JMicron USA Technology Corp. JMS567 SATA 6Gb/s bridge
  4.  
  5.  
  6. sudo nano /boot/firmware/cmdline.txt
  7. #内容はスペースで分ける(絶対に改行しない)
  8. => usb-storage.quirks=****:****:u dwc_otg.lpm_enable=・・・
  9.  
  10. sudo reboot
  11.  
  12. #確認
  13. lsusb -t
  14. => Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
  15. |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 5000M

Driver=*** の部分が uas から usb-storage に変更されていることを確認する。

sudo apt update時のエラー

  1. sudo apt update
  2.  
  3. ~省略~
  4.  
  5. Some index files failed to download. They have been ignored, or old ones used instead.

このようにエラーが出る場合に以下の対応を行う。

  1. #コマンド
  2. echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf > /dev/null

Samba(NAS化)

ラズパイに接続した外部メモリをNASとして使用したいのでSambaをインストールして設定します。

  1. #儀式
  2. sudo apt update
  3. sudo apt -y upgrade
  4.  
  5. #インストールとディレクトリの作成、権限の付与
  6. sudo apt install samba
  7. sudo mkdir /nas
  8. sudo chmod 777 /nas
  9.  
  10. #smb.confの設定
  11. sudo nano /etc/samba/smb.conf

/etc/samba/smb.conf
  1. #[global]に以下を追記
  2. browseable=no
  3.  
  4. #末尾に以下を記述
  5. [raspberrypi]
  6. comment = Raspberry Pi
  7. path = /nas
  8. guest ok = no
  9. read only = no
  10. browsable = yes

  1. #ユーザーとパスワードの設定
  2. sudo smbpasswd -a USERNAME
  3.  
  4. #Samba再起動
  5. sudo systemctl restart smbd

NFSサーバー

前項で設定したSambaで共有されたフォルダに別のラズパイからアクセスしたい場合があるのでNFSサーバーを設定します。


Sambaをインストールしているラズパイ側

  1. #儀式
  2. sudo apt update
  3. sudo apt -y upgrade
  4.  
  5. #インストール
  6. sudo apt install nfs-kernel-server
  7.  
  8. #設定
  9. sudo nano /etc/exports

/etc/exports
  1. #以下を追記 - Sambaのフォルダ 別のラズパイのIP(rw,sync,no_subtree_check)
  2. /nas 192.168.*.**(rw,sync,no_subtree_check)


別のラズパイ側

  1. #儀式
  2. sudo apt update
  3. sudo apt -y upgrade
  4.  
  5. #インストール
  6. sudo apt install nfs-common
  7.  
  8. #NFSのマウントポイントを作成、権限の付与
  9. sudo mkdir /home/pi/***
  10. sudo chmod 777 /home/pi/***
  11.  
  12. #マウント実行 - SambaがインストールされているラズパイのIP:共有フォルダ このラズパイのマウントポイント
  13. sudo mount -t nfs 192.168.*.**:/nas /home/pi/***

ディスクの速度計測

ラズパイに接続しているUSBメモリ等の外部ディスクの読み書き速度を計測したいときがあるためインストールする。

  1. sudo apt install -y hdparm
  2.  
  3. #測定
  4. sudo hdparm -t /dev/sda1
  5. =>/dev/sda1:
  6. Timing buffered disk reads: 344 MB in 3.01 seconds = 114.33 MB/sec

PrometheusとGrafana

追記

詳しく検証してないので断言できないが、PrometheusとGrafanaをインストールするとラズパイ起動時に「networkmanager-wait-online.service」で待たされるようになる。

大変便利なツールだが、CPU使用率、温度、メモリ使用率くらいしか見ておらず、わざわざインストールする必要がないと判断し、現在は使用していない。

RaspberryPiのモニタリングは必要であるため、代わりとなるプログラムをPythonで記述する。(次項)

ラズパイの管理を行う上で様々な情報が見たい場合があるので、監視ツールとしてインストールする。

  1. #Prometheusのインストール
  2. sudo apt install -y prometheus prometheus-node-exporter
  3.  
  4. #依存パッケージのインストール
  5. sudo apt install -y apt-transport-https software-properties-common wget
  6.  
  7. #GPGキーのインストール
  8. sudo mkdir -p /etc/apt/keyrings/
  9. wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
  10.  
  11. #安定リリース版のリポジトリを追加
  12. echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
  13.  
  14. #Grafanaのインストール
  15. sudo apt update
  16. sudo apt install grafana-enterprise
  17.  
  18. #Grafanaの起動
  19. sudo systemctl daemon-reload
  20. sudo systemctl start grafana-server
  21. sudo systemctl status grafana-server
  22.  
  23. #Grafanaの自動起動の有効化
  24. sudo systemctl enable grafana-server.service

後に、PrometheusのURLをGrafanaに紐づけてダッシュボードを作成する。

ダッシュボード

しかし、このままでは外出先からアクセスできないため、少し不便に感じる。

外出先からアクセスできるようにするための方法が難しく、セキュリティ面において不安が残るためDiscordBotを使用する。

  1. import discord
  2. import cv2
  3. import time
  4. from selenium import webdriver
  5. from selenium.webdriver import Chrome, ChromeOptions
  6. from selenium.webdriver.common.keys import Keys
  7. from selenium.webdriver.common.by import By
  8. from selenium.webdriver.support.ui import WebDriverWait
  9. from selenium.webdriver.support import expected_conditions
  10.  
  11. import pyvirtualdisplay
  12.  
  13. client = discord.Client(intents=discord.Intents.all())
  14.  
  15. @client.event
  16. async def on_ready():
  17. print(f'We have logged in as {client.user}')
  18.  
  19. @client.event
  20. async def on_message(message):
  21. if message.author == client.user:
  22. return
  23.  
  24. #####監視カメラ機能#####
  25. #WEBカメラの画像
  26. if message.content.startswith('$image'):
  27. camera = cv2.VideoCapture(0)
  28. ret, img = camera.read()
  29. path = "保存先のパス"
  30. cv2.imwrite(path, img)
  31.  
  32. camera.release()
  33. cv2.destroyAllWindows()
  34. await message.channel.send(file=discord.File(path))
  35. ########################
  36.  
  37. #コマンド名
  38. if message.content.startswith('$grafana'):
  39. display = pyvirtualdisplay.Display(visible=0, size=(1980, 1080))
  40. display.start()
  41.  
  42. url = 'ここにURL(例:温度のパネルとか)'
  43. options = ChromeOptions()
  44. options.add_argument('--no-sandbox')
  45. options.add_argument('--headless')
  46.  
  47. driver = Chrome(executable_path='/usr/bin/chromedriver', options=options)
  48. driver.get(url)
  49.  
  50. driver.implicitly_wait(5)
  51.  
  52. #パスワード画面
  53. user_elem = driver.find_element(By.NAME, 'user')
  54. pass_elem = driver.find_element(By.NAME, 'password')
  55.  
  56. user_elem.clear()
  57. pass_elem.clear()
  58.  
  59. #ユーザー名とパスワード
  60. user_elem.send_keys('**********')
  61. pass_elem.send_keys('**********')
  62.  
  63. driver.implicitly_wait(5)
  64.  
  65. #ログインボタンのクラス名
  66. login_btn = driver.find_element(By.CLASS_NAME, '**********')
  67. login_btn.click()
  68.  
  69. #パネルのクラス名
  70. driver.implicitly_wait(5)
  71. driver.find_element(By.CLASS_NAME, '**********')
  72.  
  73. #ズーム率とスクショの保存先
  74. driver.execute_script("document.body.style.zoom='50%'")
  75. driver.save_screenshot('ここにパス')
  76.  
  77. driver.close()
  78. display.stop()
  79.  
  80. #スクショのパス
  81. await message.channel.send(file=discord.File('ここにパス'))
  82.  
  83. #Discord Botのトークン
  84. client.run('Discord Bot Token')

このPythonファイルの一行目に以下を記述する。

儀式
  1. #!/usr/bin/python3

このPythonファイルをラズパイの起動時にサービスとして起動させたいため、サービスファイルを作成する。

サービス名は任意で設定可能です。今回は「raspberrypi」としています。

  1. cd /usr/lib/systemd/system
  2. sudo nano raspberrypi.service

raspberrypi.service
  1. [Unit]
  2. Description=Discord Bot #コメント
  3.  
  4. [Service]
  5. ExecStart=/home/pi/bot.py #フルパスで記述
  6. Restart=always
  7. Type=simple
  8.  
  9. [Install]
  10. WantedBy=multi-user.target

念のためPythonファイルとサービスファイルに最高権限を与えます。

  1. sudo chmod 777 /ここにパス

  1. #サービスの起動
  2. sudo systemctl start raspberrypi.service
  3.  
  4. #サービスの自動起動
  5. sudo systemctl enable raspberrypi.service

Discord Bot

このようにDiscord Botを経由することで、いつでも外出先からでもパネルの情報を画像で知ることができる。

コマンドの数を増やせば取得できる情報も増やすことができるが、性能の低いラズパイを使用している場合は応答速度が遅くなったり、処理が重くなる可能性があるため注意する。

Raspberry Pi4 8GBモデルでは問題なく動作した。

パネルの情報が変化しない場合は、パネルの共有URLの作成前にリフレッシュ間隔を5sに変更することで改善される。

ラズパイのモニタリング(Python)

特に監視したい項目は以下の通りである。

  • CPU温度
  • メモリ使用率
  • UPTime

今回は他にも「CPUの周波数」「CPUの電圧」も記録していく。

UPTime(合計起動時間)の記録については個別でPythonファイルを作成し、サービス化する。

その他の項目に関しては1つのPythonファイルに記述し、サービス化する。

スプレッドシートを作成し、「拡張機能」から「Apps Script」をクリックしてエディタを開き、以下を記述する。

  1. function doGet(e) {
  2. //データ
  3. var dt = e.parameter.dt;
  4. var cpu_temp = e.parameter.cpu_temp;
  5. var cpu_freq = e.parameter.cpu_freq;
  6. var cpu_voltage = e.parameter.cpu_voltage;
  7. var mem = e.parameter.mem;
  8. var uptime = e.parameter.uptime;
  9. //Activeになっているsheetを取得
  10. var sheet = SpreadsheetApp.getActiveSheet();
  11.  
  12. //書き込み
  13. sheet.appendRow([dt, cpu_temp, cpu_freq, cpu_voltage, mem, uptime]);
  14. }

「デプロイ」から「新しいデプロイ」→「ウェブアプリ」→アクセスできるユーザーを全員に設定する。

これにより、URLを知っている全員がアクセス可能な状態になるため、URLの管理には注意する。

作成したウェブアプリのURLをメモする。


事前にラズパイの「uid」と「gid」の確認をしておく。

  1. grep pi /etc/passwd
  2.  
  3. =>user:x:****:****:,,,:/home/pi:/bin/bash

UPTimeのPythonプログラムを作成する。

このプログラムではUPTime記録用のCSVを外部メモリに記録するようにしているため、起動時にマウントポイントに接続するよう、「subprocess」でシェルコマンドを実行する。

uptime.py
  1. #!/usr/bin/python3
  2. import time
  3. import csv
  4. import subprocess
  5.  
  6. #接続したままの外部メモリを起動時にマウントする(UUIDは外部メモリのもの)
  7. command_1 = "sudo -S mount -o owner,uid=****,gid=****,utf8,flush UUID='*****' /home/pi/***マウントポイント"
  8. ret_1 = subprocess.run(command_1, shell=True, capture_output=True, text=True)
  9.  
  10. #UPTimeを記録する間隔
  11. interval = 10
  12.  
  13. path = 'UPTime記録用CSVのパス'
  14.  
  15. while True:
  16. with open(path) as f:
  17. reader = f.read()
  18. # print(reader)
  19.  
  20. uptime = int(reader) + interval
  21.  
  22. with open(path, 'w') as f:
  23. writer = csv.writer(f)
  24. writer.writerow([uptime])
  25.  
  26. time.sleep(interval)

今回はCSVに記録して定期的に書き換える方法にした。

注意点として、CSVファイルは事前に作成しておき、「0」とだけ記述しておく。

次に、その他のモニタリングを行うプログラムを作成する。

monitor.py
  1. #!/usr/bin/python3
  2. import subprocess
  3. import datetime
  4. import time
  5. import sys
  6. import re
  7. import psutil
  8. import requests
  9. import subprocess
  10.  
  11. #接続したままの外部メモリを起動時にマウントする(UUIDは外部メモリのもの)
  12. command_1 = "sudo -S mount -o owner,uid=****,gid=****,utf8,flush UUID='*****' /home/pi/***マウントポイント"
  13. ret_1 = subprocess.run(command_1, shell=True, capture_output=True, text=True)
  14.  
  15. url = 'ここにデプロイしたURL'
  16.  
  17. #スプレッドシートに記録するためのリクエスト用URLを作成
  18. def mkUrl(url, dt, cpu_temp, cpu_freq, cpu_voltage, mem, uptime):
  19. newUrl = url + '?'
  20. newUrl += 'dt=' + str(dt) + '&'
  21. newUrl += 'cpu_temp=' + str(cpu_temp) + '&'
  22. newUrl += 'cpu_freq=' + str(cpu_freq) + '&'
  23. newUrl += 'cpu_voltage=' + str(cpu_voltage) + '&'
  24. newUrl += 'mem=' + str(mem) + '&'
  25. newUrl += 'uptime=' + str(uptime)
  26. return newUrl
  27.  
  28. while True:
  29. #DateTime
  30. dt = datetime.datetime.now().replace(microsecond=0)
  31.  
  32. #CPU Temp(単位:℃)
  33. temp = subprocess.run('vcgencmd measure_temp', shell=True, encoding='utf-8', stdout=subprocess.PIPE).stdout.split('=')
  34. temp = temp[1].split("'")
  35. cpu_temp = temp[0]
  36.  
  37. #CPU Freq(単位:GHz)
  38. freq = subprocess.run('vcgencmd measure_clock arm', shell=True, encoding='utf-8', stdout=subprocess.PIPE).stdout.split('=')
  39. cpu_freq = int(freq[1].replace('\n', '')) / 1000000000
  40.  
  41. #CPU Voltage(単位:V)
  42. volt = subprocess.run('vcgencmd measure_volts', shell=True, encoding='utf-8', stdout=subprocess.PIPE).stdout.split('=')
  43. volt = volt[1].split('V')
  44. cpu_voltage = volt[0]
  45.  
  46. #CPU Mem(単位:)
  47. mem = psutil.virtual_memory().percent
  48.  
  49. #UPTime(単位:秒)
  50. with open('UPTime記録用CSVのパス') as f:
  51. reader = f.read()
  52. uptime = reader
  53.  
  54. #データの送信
  55. upUrl = mkUrl(url, dt, cpu_temp, cpu_freq, cpu_voltage, mem, uptime)
  56. requests.get(upUrl)
  57.  
  58. #プログラムを実行する間隔(15分)
  59. time.sleep(900)

このプログラムで「UPTime」の記録も一緒にスプレッドシートに記録する仕組みになっている。

プログラム完成後は前項で記載してあるように、各Pythonファイルをサービス化して自動起動を有効にする。

実際に記録されたスプレッドシートは以下の通りである。

スプレッドシート

一行目のヘッダーは事前に入力したものである。

Writer

アイコン
Python×Raspi IoTシステム・Bot・ラズパイの記録
  • プログラミング
  • IoT
  • Python
\FOLLOW ME/ 𝕏

Ranking

blogmura_pvcount

Community

Search