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

2024/07/15

ラズパイ

  • B!
サムネ
サムネ

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

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

$ lsb_release -a

No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 12 (bookworm)
Release:        12
Codename:       bookworm

OS書き込み

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

OS書き込み

自動ログインの設定

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

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
    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にする。

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

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

exit 0

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

IPの固定化

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

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

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

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

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

有線LAN
sudo nmcli connection modify eth0 ipv4.addresses 固定したいIP/24
sudo nmcli connection modify eth0 ipv4.gateway デフォルトゲートウェイ
sudo nmcli connection modify eth0 ipv4.dns 8.8.8.8,8.8.4.4
sudo nmcli connection modify eth0 ipv4.method manual
sudo nmcli connection up eth0

#設定の確認
nmcli -f ipv4 connection show eth0

#設定ファイルの場所
sudo nano /etc/NetworkManager/system-connections/'Wired connection 1.nmconnection'

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

Wi-Fi
sudo nmcli connection modify preconfigured ipv4.method manual ipv4.addresses 固定したいIP/24 ipv4.gateway デフォルトゲートウェイ ipv4.dns 8.8.8.8,8.8.4.4
sudo nmcli device disconnect wlan0 
sudo nmcli device connect wlan0

#設定ファイルの場所
sudo nano  /etc/NetworkManager/system-connections/preconfigured.nmconnection

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

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

sudo nano /boot/firmware/config.txt

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

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

#接続状況の確認
nmcli device status
nmcli connection show

ネットワーク速度テスト

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

sudo apt install speedtest-cli

#実行コマンド
speedtest-cli

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

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

SWAPの無効化

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

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

#SWAPの確認
free -h

sudo swapoff --all
sudo systemctl stop dphys-swapfile
sudo systemctl disable dphys-swapfile
systemctl status dphys-swapfile

free -h

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

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

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

sudo umount -l /dev/sda1 #例

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

lsusb -t

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

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

lsusb
#IDをメモする
=> Bus 002 Device 002: ID ****:**** JMicron Technology Corp. / JMicron USA Technology Corp. JMS567 SATA 6Gb/s bridge


sudo nano /boot/firmware/cmdline.txt
#内容はスペースで分ける(絶対に改行しない)
=> usb-storage.quirks=****:****:u dwc_otg.lpm_enable=・・・

sudo reboot

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

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

sudo apt update時のエラー

sudo apt update

~省略~

Some index files failed to download. They have been ignored, or old ones used instead.

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

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

Samba(NAS化)

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

#儀式
sudo apt update
sudo apt -y upgrade

#インストールとディレクトリの作成、権限の付与
sudo apt install samba
sudo mkdir /nas
sudo chmod 777 /nas

#smb.confの設定
sudo nano /etc/samba/smb.conf

/etc/samba/smb.conf
#[global]に以下を追記
browseable=no

#末尾に以下を記述
[raspberrypi]
    comment = Raspberry Pi
    path = /nas
    guest ok = no
    read only = no
    browsable = yes

#ユーザーとパスワードの設定
sudo smbpasswd -a USERNAME

#Samba再起動
sudo systemctl restart smbd

NFSサーバー

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


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

#儀式
sudo apt update
sudo apt -y upgrade

#インストール
sudo apt install nfs-kernel-server

#設定
sudo nano /etc/exports

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


別のラズパイ側

#儀式
sudo apt update
sudo apt -y upgrade

#インストール
sudo apt install nfs-common

#NFSのマウントポイントを作成、権限の付与
sudo mkdir /home/pi/***
sudo chmod 777 /home/pi/***

#マウント実行 - SambaがインストールされているラズパイのIP:共有フォルダ このラズパイのマウントポイント
sudo mount -t nfs 192.168.*.**:/nas /home/pi/***

ディスクの速度計測

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

sudo apt install -y hdparm

#測定
sudo hdparm -t /dev/sda1
=>/dev/sda1:
   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で記述する。(次項)

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

#Prometheusのインストール
sudo apt install -y prometheus prometheus-node-exporter

#依存パッケージのインストール
sudo apt install -y apt-transport-https software-properties-common wget

#GPGキーのインストール
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null

#安定リリース版のリポジトリを追加
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

#Grafanaのインストール
sudo apt update
sudo apt install grafana-enterprise

#Grafanaの起動
sudo systemctl daemon-reload
sudo systemctl start grafana-server
sudo systemctl status grafana-server

#Grafanaの自動起動の有効化
sudo systemctl enable grafana-server.service

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

ダッシュボード

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

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

import discord
import cv2
import time
from selenium import webdriver
from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions

import pyvirtualdisplay

client = discord.Client(intents=discord.Intents.all())

@client.event
async def on_ready():
    print(f'We have logged in as {client.user}')

@client.event
async def on_message(message):
    if message.author == client.user:
        return

    #####監視カメラ機能#####
    #WEBカメラの画像
    if message.content.startswith('$image'):
        camera = cv2.VideoCapture(0)
        ret, img = camera.read()
        path = "保存先のパス"
        cv2.imwrite(path, img)

        camera.release()
        cv2.destroyAllWindows()
        await message.channel.send(file=discord.File(path))
    ########################

    #コマンド名
    if message.content.startswith('$grafana'):
        display = pyvirtualdisplay.Display(visible=0, size=(1980, 1080))
        display.start()

        url = 'ここにURL(例:温度のパネルとか)'
        options = ChromeOptions()
        options.add_argument('--no-sandbox')
        options.add_argument('--headless')

        driver = Chrome(executable_path='/usr/bin/chromedriver', options=options)
        driver.get(url)

        driver.implicitly_wait(5)

        #パスワード画面
        user_elem = driver.find_element(By.NAME, 'user')
        pass_elem = driver.find_element(By.NAME, 'password')

        user_elem.clear()
        pass_elem.clear()

        #ユーザー名とパスワード
        user_elem.send_keys('**********')
        pass_elem.send_keys('**********')

        driver.implicitly_wait(5)

        #ログインボタンのクラス名
        login_btn = driver.find_element(By.CLASS_NAME, '**********')
        login_btn.click()

        #パネルのクラス名
        driver.implicitly_wait(5)
        driver.find_element(By.CLASS_NAME, '**********')

        #ズーム率とスクショの保存先
        driver.execute_script("document.body.style.zoom='50%'")
        driver.save_screenshot('ここにパス')

        driver.close()
        display.stop()

        #スクショのパス
        await message.channel.send(file=discord.File('ここにパス'))

#Discord Botのトークン
client.run('Discord Bot Token')

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

儀式
#!/usr/bin/python3

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

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

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

raspberrypi.service
[Unit]
Description=Discord Bot #コメント

[Service]
ExecStart=/home/pi/bot.py #フルパスで記述
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target

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

sudo chmod 777 /ここにパス

#サービスの起動
sudo systemctl start raspberrypi.service

#サービスの自動起動
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」をクリックしてエディタを開き、以下を記述する。

function doGet(e) {
  //データ
  var dt = e.parameter.dt;
  var cpu_temp = e.parameter.cpu_temp;
  var cpu_freq = e.parameter.cpu_freq;
  var cpu_voltage = e.parameter.cpu_voltage;
  var mem = e.parameter.mem;
  var uptime = e.parameter.uptime;
  
  //Activeになっているsheetを取得
  var sheet = SpreadsheetApp.getActiveSheet();

  //書き込み
  sheet.appendRow([dt, cpu_temp, cpu_freq, cpu_voltage, mem, uptime]);
}

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

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

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


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

grep pi /etc/passwd

=>user:x:****:****:,,,:/home/pi:/bin/bash

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

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

uptime.py
#!/usr/bin/python3
import time
import csv
import subprocess

#接続したままの外部メモリを起動時にマウントする(UUIDは外部メモリのもの)
command_1 = "sudo -S mount -o owner,uid=****,gid=****,utf8,flush UUID='*****' /home/pi/***マウントポイント"
ret_1 = subprocess.run(command_1, shell=True, capture_output=True, text=True)

#UPTimeを記録する間隔
interval = 10

path = 'UPTime記録用CSVのパス'

while True:
    with open(path) as f:
        reader = f.read()
        # print(reader)

    uptime = int(reader) + interval

    with open(path, 'w') as f:
        writer = csv.writer(f)
        writer.writerow([uptime])

    time.sleep(interval)

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

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

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

monitor.py
#!/usr/bin/python3
import subprocess
import datetime
import time
import sys
import re
import psutil
import requests
import subprocess

#接続したままの外部メモリを起動時にマウントする(UUIDは外部メモリのもの)
command_1 = "sudo -S mount -o owner,uid=****,gid=****,utf8,flush UUID='*****' /home/pi/***マウントポイント"
ret_1 = subprocess.run(command_1, shell=True, capture_output=True, text=True)

url = 'ここにデプロイしたURL'

#スプレッドシートに記録するためのリクエスト用URLを作成
def mkUrl(url, dt, cpu_temp, cpu_freq, cpu_voltage, mem, uptime):
    newUrl = url + '?'
    newUrl += 'dt=' + str(dt) + '&'
    newUrl += 'cpu_temp=' + str(cpu_temp) + '&'
    newUrl += 'cpu_freq=' + str(cpu_freq) + '&'
    newUrl += 'cpu_voltage=' + str(cpu_voltage) + '&'
    newUrl += 'mem=' + str(mem) + '&'
    newUrl += 'uptime=' + str(uptime)
    return newUrl

while True:
   #DateTime
   dt = datetime.datetime.now().replace(microsecond=0)

   #CPU Temp(単位:℃)
   temp = subprocess.run('vcgencmd measure_temp', shell=True, encoding='utf-8', stdout=subprocess.PIPE).stdout.split('=')
   temp = temp[1].split("'")
   cpu_temp = temp[0]

   #CPU Freq(単位:GHz)
   freq = subprocess.run('vcgencmd measure_clock arm', shell=True, encoding='utf-8', stdout=subprocess.PIPE).stdout.split('=')
   cpu_freq = int(freq[1].replace('\n', '')) / 1000000000

   #CPU Voltage(単位:V)
   volt = subprocess.run('vcgencmd measure_volts', shell=True, encoding='utf-8', stdout=subprocess.PIPE).stdout.split('=')
   volt = volt[1].split('V')
   cpu_voltage = volt[0]

   #CPU Mem(単位:)
   mem = psutil.virtual_memory().percent

   #UPTime(単位:秒)
   with open('UPTime記録用CSVのパス') as f:
       reader = f.read()
   uptime = reader

   #データの送信
   upUrl = mkUrl(url, dt, cpu_temp, cpu_freq, cpu_voltage, mem, uptime)
   requests.get(upUrl)

   #プログラムを実行する間隔(15分)
   time.sleep(900)

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

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

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

スプレッドシート

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

Writer

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

Ranking

Community

Search