ラベル raspberry pi の投稿を表示しています。 すべての投稿を表示
ラベル raspberry pi の投稿を表示しています。 すべての投稿を表示

2024年3月3日日曜日

raspberry pi : 固定IPアドレスにする (dhcpcd.conf が無い場合)

目的:

nmcli を使用して 固定IPアドレス を設定する。

背景:

Raspberry pi 5 で 固定IPアドレスを設定しようとしたところ、 /etc/dhcpcd.conf が存在しなかった。
OS の バージョンが bookworm になって 設定方法が変わった模様。

手順:

NetworkManager (nmcli) を使用して設定を行う。
設定は
  1. コマンドで設定する。
  2. 設定ファイルを編集して設定する。

のどちらでも可能。
nmcli の コマンド は コマンドが補完できるまで短縮可能 
例 : nmcli connection show   →   nmcli c s

1.コマンドで設定。

  1. 接続名の確認
    nmcli connection show
    で 接続名を確認
    NAME           UUID                                  TYPE      DEVICE 
    有線接続 1     xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  ethernet  eth0   
    preconfigured  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  wifi      wlan0  
    lo             xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  loopback  lo
    
    以降、設定等で 接続名(NAME)を使用するが、接続名 が日本語(2バイトコード) や スペース が含まれている場合は " (ダブルコーテーション) で括って使用する。
    但し、認識できない等の不具合を発生する場合も在りうるため、1バイトコードに変更した方が良い。(手順は こちら )

  2. IPv4 IPアドレス等を設定する
    IPアドレス
    sudo nmcli connection modify [接続名] ipv4.addresses "xxx.xxx.xxx.xxx/24"
    デフォルトゲートウェイ
    sudo nmcli connection modify [接続名] ipv4.gateway "xxx.xxx.xxx.xxx"
    DNS
    sudo nmcli connection modify [接続名] ipv4.dns "xxx.xxx.xxx.xxx"
    (DNS の IPアドレスは スペースで区切って 複数指定可能 )

  3. IPアドレス を 手動設定に変更する。
    sudo nmcli connect modify [接続名]  ipv4.method manual
    この設定は、IPアドレスの設定を行った後に行わないとエラーとなる。

  4. 反映
    sudo nmcli con up eth0

2. 設定ファイルを編集して設定。

設定ファイルは 以下となる。(接続名毎に設定ファイルがある)
/etc/NetworkManager/system-connections/[接続名].nmconnection
  1. 接続名の確認
    nmcli connection show
    で 接続名を確認

  2. 設定ファイルを編集 設定ファイルの IPv4 の部分を書き換える。(br />
    hidden=false
    [ipv4]
    method=auto
    [ipv6]
    hidden=false
    [ipv4]
    address1=[IPアドレス]/24,[ゲートウェイアドレス]
    dns=[DNSアドレス1;DNSアドレス2];
    method=manual

    [ipv6]

  3. 反映
    sudo nmcli connection reload
    sudo nmcli con up preconfigured

* 接続名を変更する

接続名の変更は、古い接続名を削除して新しい接続名を追加することで行う。
接続名が日本語(2バイトコード) の場合、1バイトコードに変える。

  1. 接続名が日本語の接続を切断する
    sudo nmcli connection delete [UUID]
  2. 新しい接続名で接続を追加する
    sudo nmcli connection add type ethernet ifname [デバイス名] con-name [接続名]


2023年11月19日日曜日

raspberry pi : FANをPWM制御する (C言語)

目的:

ラズベリーパイのFAN (PWM制御対応のFAN> を PWM 制御 する。

背景:

ラズベリーパイのケースについているFAN から音が出るようになった。
(5V ファン を 3.3V 駆動 )
この為、PWM制御対応の5V FAN を購入し、説明書通り、/boot/config.txt に
dtoverlay=gpio-fan,gpiopin=18,temp=55000
を追加したところ、 指定温度 (55℃) 以上 で ON, 未満で OFF となり、FAN が 定期的に 全力回転 していた。(PWM制御ではなく、 ON/OFF 制御 )
この為、PWM制御 (回転数制御) できるようにする。

概要

PWM制御については、「C言語で LED 調光 (pigpio を使用した PWM 制御) 」を参照。
pigpiod(デーモン)を使用した hardware_PWM (ユーザ権限で実行可能) を使用し、指定温度範囲で 段階的に FAN回転数 を変える様にする。
尚、コード作成は C言語 で行う。

構成

raspberry pi : raspberry pi 4
FAN : PWM制御端子付き の 5V FAN
使用 GPIO : 18 pin


PWM FAN 制御用コード

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pigpiod_if2.h>

int get_temp(void) {
  static int tmp = 0;
  FILE *fp;
  char rdt[16];

  fp = fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","r") ;
  if (fp != NULL ) {
    fgets(rdt,16,fp) ;
    fclose(fp);
    tmp = atoi(rdt) / 1000 ;
  }

  return tmp ;
}

void usage(void)
{
  printf("Usage: pigpio_pwnfan [option]\n");
  printf("\n");
  printf("  option\n (default)") ;
  printf("    -l n ... Low temperature (50)    'C\n");
  printf("    -h n ... hi  temperature (60)    'C\n");
  printf("    -p n ... PWM output pin  (18)    12/18(ch0) or 13/19(ch1)\n");
  printf("    -f n ... PWM Frequency   (10000) Hz\n");
  printf("\n");
}

int main(int argc, char **argv) {
  int gpio_pin = 18;      // hardware PWM Pin
  int pwm_freq = 10000;   // hardware PWM frequency
  int pwm_duty = 0 ;      // hardware PWM duty
  int tmp_low  = 50;      // cold temperature
  int tmp_hi   = 60;      // hot temperature
  int temp     = 0 ;      // detect twmperature
  int pi       = 0 ;
  int opt      = 0 ;

  // command line option 
  while ((opt = getopt(argc, argv, "l:h:p:f:")) != -1) {
    switch (opt) {
      case 'l':
        tmp_low = atoi(optarg);
        break;
      case 'h':
        tmp_hi  = atoi(optarg);
        break;
      case 'p':
        switch((gpio_pin = atoi(optarg))) {
          case 12:
          case 13:
          case 18:
          case 19:
            break;
          default:
            usage();
            exit(1);
        }
        break;
      case 'f':
        pwm_freq = atoi(optarg);
        break;
      default:
        printf("\n");
        usage();
        exit(1);
    }
  }

  if (tmp_low >= tmp_hi)
  {
    usage();
    exit(1);
  }


  // pigpio start
  pi = pigpio_start(0,0) ;
  if (pi<0) {
    printf ("pigpio start error !!") ;
    exit(1) ;
  }

  // PWM control
  while (1)
  {
    temp = get_temp();
    if (temp <= tmp_low) {
      pwm_duty = 0;
    } else if(temp >= tmp_hi) {
      pwm_duty = 1000000 ;       // 100%
    }else {
      pwm_duty = ((temp - tmp_low) * 1000000) / (tmp_hi - tmp_low) ;
    }

    hardware_PWM(pi,gpio_pin, pwm_freq, pwm_duty) ;

    sleep(10);
  }


  return 0;
}

コード概要

  1. get_temp(void)
    raspberry pi のCPU温度を取得する。
    温度の取得は /sys/devices/virtual/thermal/thermal_zone0/temp を読み込む事で行う。
  2. usage(void)
    オプション不正時の書式の表示を行う。
  3. main(int argc,char **argv) PWM FAN 制御 本体。
    1. command line option 解析部分 getopt を して オプションの解析を行う。
      unistd.h をインクルードする必要がある。
      -l : 下限温度。この温度より下は FAN停止。(省力時 50℃) -h : 上限温度。この温度より上は FAN全速。(省略時 60℃) -p : GPIO PIN番号。12/18(ch0) 又は 13/19(ch1) (省略時 18) -f : PWM 周波数 (省略時 10000 (10KHz) )
  4. pigpio start pigpio_start(0,9) (pigpio の 初期化) を実行。 戻り値が負の場合、異常終了。
  5. PWM control PWM 制御 本体。 設定温度の間、検出温度の応じてデューティを 0~100% の間で変化させる。 無限ループで、 温度の取得, PWM 設定 を行った後、10秒間 スリープする。 ( 10秒間隔で PWM制御 )

コンパイル

gcc -Wall -pthread -o pigpio_pwmfan pigpio_pwmfan.c -lpigpiod_if2 -lrt

実行

pigpiod 開始

sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service

実行 (動作確認)

pigpio_pwmfan&
で実行し、FAN がPWM制御されていること(全速でないこと)を確認する。

停止

作成した FAN制御プログラムは サービスとして実行するため、動作確認で実行したプロセスを以下で終了させる。
ps
で pigpio_pwmfan の PIDを確認し、
kill [PID]
で pigpio_pwmfan を終了させる。

サービスへの登録

再起動時等、自動で開始するようにサービスに登録する。

ユニット定義ファイルの作成

/etc/systemd/system に ユニット定義ファイルを作成する。

ユニット定義ファイル例
[Unit]
# サービスの説明。内容は任意
Description=PWM FAN Control
# このUnitより先に起動するべきUnitを設定
After=local-fs.target
  
[Service]
# 実行するコマンドやスクリプトを記述
ExecStart=/usr/local/bin/pigpio_pwmfan
# サービス停止時の Kill する単位を設定
KillMode=process
# プロセスの起動方法を指定
Type=simple
# サービス停止時の再起動条件 (no は再起動しない)
Restart=always
 
[Install]
# 該当ユニットへの弱い依存関係を設定
WantedBy=multi-user.target

FAN制御プログラムの サービス登録、実行

sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service






2023年11月6日月曜日

raspberry pi : C言語で LED 調光 (pigpio を使用した PWM 制御)

目的:

WiringPi は 非推奨になったとのことの為、pigpio を使用して PWM 制御を 行う。

概要:

pigpio による ハードウェアPWM を使用する場合、以下の2種類がある。
  1. gpioHardwarePWM を使用
    この場合、
    1. pigpiod (デーモン) を使用しない。( 動作していてはいけない )
    2. 実行は sudo を付けて行う必要がある。(管理者権限が必要)
  2. hardware_PWM を使用
    この場合、
    1. 実行 は sudo を 付けて実行する必要がある。
    2. 管理者権限は不要。
以下、この2種類について、記す。
( 参考 : The pigpio library )

gpioHardwarePWM による PWN 制御:

書式

gpioHardwarePWM(gpio番号, PWM周波数, PWMデューティ)
PWM周波数は 0 ~ 125000000  ( 0 ~ 125MHz)
PWMデューティ は 0 ~ 1000000 ( 0 ~ 100% )

注意事項等

インクルードファイル : pigpio.h
最初に、初期化 として gpioInitialise() を実行する必要がある。

サンプルコード

#include <pigpio.h>

#define GPIO_PWM1 18
#define GPIO_PWM2 19

#define PMW_FREQ    10000

int main(void)
{
    int ret = gpioInitialise();
    if (ret < 0)
    {
        return ret;
    }
    else
    {
        gpioHardwarePWM(GPIO_PWM1, PMW_FREQ, 100000);
        gpioHardwarePWM(GPIO_PWM2, PMW_FREQ, 700000);

        gpioSleep(PI_TIME_RELATIVE,5,0) ;

        gpioHardwarePWM(GPIO_PWM1, PMW_FREQ, 700000);
        gpioHardwarePWM(GPIO_PWM2, PMW_FREQ, 100000);

        gpioSleep(PI_TIME_RELATIVE,5,0) ;

        gpioHardwarePWM(GPIO_PWM1, PMW_FREQ, 0);
        gpioHardwarePWM(GPIO_PWM2, PMW_FREQ, 0);

        gpioTerminate();
    }

    return ret;
}

コンパイル

gcc -Wall -pthread -o pigpio_pwm pigpio_pwm.c -lpigpio -lrt
pigpio.h をインクルードしているため、 -lpigpio が必要。

実行

sudo ./pigpio_pwm
で gpio 18, 19 に PWMのパルス信号が 出力される。
サンプルコードでは 最初に出力した 5秒後に Duty を変えて出力。
その 5秒後に 出力を 停止する。

その他

pigpio を使用する場合は、管理者権限で実行する必要がある。( sudo で実行等)
pigpiod のデーモンは不要。( pigpiod が 動いていると実行できない )
通常の gpio へのアクセスは gpioWrite, gpioRead を使用する。

hardware_PWM による PWN 制御

pigpiod の注意事項

hardware_PWM を使用するには pigpiod を走らせる必要があるが、
pigpiod を走らせると、CPU のパワーを消費してしまう。
これは、ソフトウェア PWN の為 とのこと。
ソフトウェア PWM を使用しないのであれば、サンプリング機能を無効にする
オプション(-m) を付加することで、CPU の消費が少なくなる。

サンプリング機能を無効にする方法 ( CPUの使用率を下げる為)

設定は、 /lib/systemd/system/pigpiod.service を編集して行う。
pigpiod.service :
1 [Unit]
2 Description=Daemon required to control GPIO pins via pigpio
3 [Service]
4 ExecStart=/usr/bin/pigpiod -l -m
5 ExecStop=/bin/systemctl kill pigpiod
6 Type=forking
7 [Install]
8 WantedBy=multi-user.target
上記の通り、 ExecStart の ところに -m を追加する。

pigpiod 開始

pigpiod (デーモン) の開始は、
sudo systemctl enable pigpiod.service
sudo systemctl start pigpiod.service
で行う。
尚、pigpiod の停止は、
sudo systemctl disable pigpiod.service
sudo systemctl stop pigpiod.service
で行う。

書式

hardware_PWM(pi, gpio番号, PWM周波数, PWMデューティ)
pi は pigpio_start の戻り値
PWM周波数は 0 ~ 125000000  ( 0 ~ 125MHz)
PWMデューティ は 0 ~ 1000000 ( 0 ~ 100% )

注意事項等

インクルードファイル : pigpiod_if2.h
最初に、初期化 として pigpio_start(0,0) を実行する必要がある。

サンプルコード

#include <pigpiod_if2.h>

#define GPIO_PWM1 18
#define GPIO_PWM2 19

#define PMW_FREQ    10000

int main(void)
{
    int pi = pigpio_start(0,0) ;
    if (pi < 0)
    {
        return pi;
    }
    else
    {
        hardware_PWM(pi,GPIO_PWM1, PMW_FREQ, 100000);
        hardware_PWM(pi,GPIO_PWM2, PMW_FREQ, 700000);

        time_sleep(5) ;

        hardware_PWM(pi,GPIO_PWM1, PMW_FREQ, 700000);
        hardware_PWM(pi,GPIO_PWM2, PMW_FREQ, 100000);

        time_sleep(5) ;

        hardware_PWM(pi,GPIO_PWM1, PMW_FREQ, 0);
        hardware_PWM(pi,GPIO_PWM2, PMW_FREQ, 0);
    }

    return pi ;
}

コンパイル

gcc -Wall -pthread -o pigpio_pwm pigpio_pwm.c -lpigpiod_if2 -lrt
pigpiod_if2.h をインクルードしているため、 -lpigpiod_if2 が必要。

実行

./pigpio_pwm
で gpio 18, 19 に PWMのパルス信号が 出力される。
サンプルコードでは 最初に出力した 5秒後に Duty を変えて出力。
その 5秒後に 出力を 停止する。

その他 注意事項等

pigpio を使用する場合は、実行時に sudo は不要。
pigpiod のデーモンが必要。
通常の gpio へのアクセスは gpio_write, gpio_read を使用する。

pigpiod_if2.h


2021年9月25日土曜日

raspberry pi : apt upgrade で エラー発生 ( Fatal Python error )

現象:

apt upgrade 実行時、Fatal Python error が発生し、upgrade できない。

原因:

不明。

対処 (暫定) :

OS 再インストール

経緯:

久しぶりに apt update, apt upgrade を行ったところ、apt upgrade で以下の様なエラーが発生。

 :
 :
取得:408 http://archive.raspberrypi.org/debian buster/main armhf vlc-plugin-visualization armhf 3.0.12-0+deb10u1+rpt2 [142 kB]
取得:409 http://archive.raspberrypi.org/debian buster/main armhf cups-pk-helper armhf 0.2.6-1+rpi1 [69.0 kB]
513 MB を 3分 18秒 で取得しました (2,593 kB/s)
Fatal Python error: initimport: can't import _frozen_importlib
ValueError: bad marshal data (unknown type code)

Current thread 0xb6faaad0 (most recent call first):
Aborted
E: 子プロセス /usr/bin/apt-listchanges --apt || test $? -lt 10 がエラーコード (1) を返しました
E: Failure running script /usr/bin/apt-listchanges --apt || test $? -lt 10
$

対処として、以下を行ったが、効果なし。

  1. .pycファイルを削除 --- 効果なし
    sudo find /usr -name '*.pyc' -delete
    で *.pyc を削除して apt upgrade を実施したが、効果なし
  2. python, python3 の再インストール --- 効果なし
    ソースコード を wget して、コンパイル/インストール したが、効果なし

 また、ufw status 等でも 同様のエラーが発生。
 1カ月程古い バックアップイメージ で 復元したが、現象変わらず。
 何かのファイルが壊れているのかもしれないが、原因不明で  upgrade, install ができず、このままにしておくわけにはいかない。
修復を諦め、最新の OS バージョンで再度インストールを実施した。

raspberry pi : FTPサーバーのインストール

 目的:

FTPサーバーをインストールして Windows等 からのファイルアクセスができるようにする。

手順:

以下の手順で vsftpd をインストールする。
  1. パッケージリストの更新、パッケージのアップデートを行う。
    sudo apt update
    sudo apt upgrade

  2. vsftpd のインストールを行う。
    sudo apt install vsftpd
     
  3. raspberry pi 起動時に vsftpd も立ち上げる様にする。
    sudo systemctl enable vsftpd

  4. /etc/vsftpd.conf を修正して ファイルの書き込みを許可する。
    sudo vi /etc/vsftpd.conf

    #write_enable=YES

    write_enable がコメントアウトされているので、#を消して有効にする。

ファイル転送:

 Windows PC 等 から、FTPクライアントソフト ( WinSCP 等 ) からアクセスし、ファイル転送できる事を確認する。


 

2020年12月9日水曜日

raspberry pi : WEB から LED 調光 ( php - C言語 間通信 )

 目的:

WEB画面から raspberry pi に 接続した LED の PWM制御による 調光 を行う。
php から Cプログラム へ メッセージキュー を使用したプロセス間通信を使用する。

環境/構成:

環境/構成は、 WEB から  LED ON/OFF と同じ。 
プロセス間通信については、WEB から  LED ON/OFF ( php - C言語 間通信 ) を参照。
PWM制御については、C言語で LED 調光 (PWM 制御) を参照。

phpファイル(WEB画面):

WEB画面は、ESP32/arduino:LED調光_スライダーで明るさを調整 と同じ画面。


以下に、phpファイル (HTML) を示す。

<?php
  $QKEY = 1111;
  $QUEUE = msg_get_queue($QKEY, 0666);

  session_start() ;
  if ($_SESSION['led_val'] == NULL ) $_SESSION['led_val'] = 0 ;
 
  if ($_GET['led_v'] != NULL) {
    $_SESSION['led_val'] = $_GET['led_v'] ;
    msg_send($QUEUE, "1111", "set_ledval " . $_SESSION['led_val'] . "\0" , FALSE) ;
    }

  if ($_GET['led_s'] != NULL) {
    $_SESSION['led_val'] = $_GET['led_v'] ;
    msg_send($QUEUE, "1111", "set_ledval " . $_SESSION['led_val'] . "\0" , FALSE) ;
    }

  if ($_GET['on'] == "ON") {
    $_SESSION['led_val'] = "255" ;
    msg_send($QUEUE, "1111", "led_on\0" , FALSE) ;
    }
  
  if ($_GET['off'] == "OFF") {
    $_SESSION['led_val'] = "0" ;
    msg_send($QUEUE, "1111", "led_off\0" , FALSE) ;
    }

  $led_brightness = $_SESSION['led_val'] ;
?>

<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>
<style>input.button  {margin:8px;width:100px;}
       input.button2 {margin-left:8px; width:40px;}
       input.text    {margin-left:8px; width:25px;}
       input.slid    {width:230px;}
       div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
       </style>
<title>Color LED Controller</title></head>

<body>
<div><p>LED ON/OFF</p>
  <form method='get' style='text-align:left' >
    <span style='padding-left:15pt; font-size:8pt ;text-align:left'> LED brightness (0-255)</span>
    <input class='text'  type='text' name='led_v' id='led_v' value=<?=$led_brightness?> >
    <input class='button2' type='submit' name='set' value='SET'>
  </form>

  <form name='slidform' method='get' style='text-align:left'>
    <input class='slid' type='range' name='led_s' value=<?=$led_brightness?> min='0' max='255' step='1' onchange='setval(this.value)' oninput='setval(this.value)' >
  </form> 

  <form method='get'>
    <input class='button' type='submit' name='on' value='ON'><input class='button' type='submit' name='off' value='OFF'><br>
  </form>

  </div>


<script>
function setval(ledval){
  var xhr = new XMLHttpRequest();
  xhr.open('get', 'pwm_resp.php?slid='+ledval );
  xhr.timeout = 1000 ;
  xhr.setRequestHeader('Cache-Control', 'no-cache');
  xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
  xhr.responseType = 'document' ;

  xhr.onreadystatechange = function() {
      if( (xhr.readyState == 4) && (xhr.status == 200) ) {
          document.getElementById('led_v').value = xhr.response.getElementById('output1').innerHTML;
      }
  }
  xhr.ontimeout = function(e) {
      xhr.abort() ;
  }
  xhr.send();
}

</script>
</body>
</html>

<?php 
  $led_brightness = $_GET['slid'] ;
  $QKEY = 1111;
  $QUEUE = msg_get_queue($QKEY, 0666);

  msg_send($QUEUE, "1111", "set_slidval " . $led_brightness . "\0" , FALSE) ;
?>

<!DOCTYPE html><html lang='ja'>
  <head> <title>Color LED Controller</title></head>
  <body>

  <output id='output1'> <?=$led_brightness?> </output>

  </body> </html>

処理の流れ:

  • php 本体では、各 GET 要求を受けたとき、メッセージキューに LED 操作のコマンドを送信する。また、HTML 中の変数($led_brightness) に値を設定する。
  • HTML中の変数($led_brightness) は、php のショートタグ( <?=*** ?> ) を使用して値に置き換える。
  • スライダー操作時は、javascript で XHRを使用して 値を XHRレスポンス用 php に送信する。
  • XHR レスポンス用 php では、送信された値を受け、メッセージキューに LED 操作のコマンドを送信し、受信した値をそのままレスポンスとして返す。ここでは、HTML(テキスト) でレスポンスを返している。

各処理の内容については、上述の参照ページを参照。

Cプログラム(LED調光):

Cプログラムは、 WEB から  LED ON/OFF ( php - C言語 間通信 ) の LED ON, OFF を PWM制御 ( C言語で LED 調光 (PWM 制御) ) に置き換えたものとなる。
プログラムを以下に示す。
#include <wiringPi.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <termios.h>
#include <fcntl.h>

// *****************************************************************************
// * 定義等                                                                    *
// *****************************************************************************
// メッセージキュー 用 定義 ----------------------------------------------------
#define BUFFSIZE 256                             // バッファサイズ
#define QKEY     (key_t)1111                     // メッセージキューの key
                                                 //
struct msgbuf{                                   // メッセージの構造体
  long int type;                                 // type は long int であること。
  char data[BUFFSIZE];                           // 
};                                               //
                                                 //
// LED ON/OFF 用 定義 ----------------------------------------------------------
#define led_pin 12                               // LED を接続する GPIO #
                                                 //
// *****************************************************************************
// * キーイベントの取得                                                        *
// *****************************************************************************
                                                 //
int kbhit(void) {                                //
  struct termios oldt, newt;                     //
  int ch;                                        //
  int oldf;                                      //
                                                 //
  tcgetattr(STDIN_FILENO, &oldt);                //
  newt = oldt;                                   //
  newt.c_lflag &= ~(ICANON | ECHO);              //
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);       //
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);        //
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);  //
                                                 //
  ch = getchar();                                //
                                                 //
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);       //
  fcntl(STDIN_FILENO, F_SETFL, oldf);            //
                                                 //
  if (ch != EOF) {                               //
  ungetc(ch, stdin);                             //
  return 1;                                      //
  }                                              //
                                                 //
  return 0;                                      //
}                                                //
                                                 //
// *****************************************************************************
// * メイン 関数                                                               *
// *****************************************************************************
int main() {                                     //
  int msqid;                                     // メッセージキュー ID 
  struct msgbuf message;                         // メッセージ 
  long int read_type = 0 ;                       // リードするメッセージタイプ
  char c ;                                       // 1文字入力用
  char buf[128] ;                                // キーボード入力用のバッファ
  int  p_buf = 0 ;                               // 入力位置
  char *cmd ;                                    // コマンド用バッファ
  char *prm1 ;                                   // パラメータ1用バッファ
  int  val = 0 ;                                 // 設定値
                                                 //
  // メッセージキューの作成,取得 -----------------------------------------------
  //   誰でも読み書き可能なキューを作成して、ID を取得する                    --
  errno = 0;                                     //
  if( (                                          // 
        msqid = msgget(QKEY, 0666 | IPC_CREAT)   // 0666:アクセス許可パラメータ
      ) == -1 ) {                                //
    perror("msgget failure");                    //   作成失敗時の処理
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  // wiringpi の設定 -----------------------------------------------------------
  wiringPiSetupGpio() ;                          //
  pinMode (led_pin, PWM_OUTPUT) ;                //   LED 調光
  pwmSetMode(PWM_MODE_MS) ;                      // PWM モード設定
  pwmSetClock(40) ;                              // PWM 分周比設定(レンジ当たりのクロック数)
  pwmSetRange(255) ;                             // PWM 分解能設定(1周期当たりのレンジ数)
                                                 //
  // メッセージを受信して LED の ON/OFF を行う ---------------------------------
  while(1){
    errno = 0 ;                                  //
    if (!(msgrcv( msqid, &message, BUFFSIZE,     // メッセージの受信 
                 read_type, IPC_NOWAIT) == -1)   //
        )                                        //
    {                                            // メッセージ受信時の処理
      // メッセージをコマンドとパラメータに分割 -//
      cmd = strtok(message.data, " ") ;          // 最初の文字列(" "まで) をコマンド
      prm1 = strtok(NULL, " ") ;                 // 次の文字列を パラメータ1
      printf("command : %s %s\n",cmd,prm1);      // 表示
                                                 //
      if (strcmp(cmd,"led_on") == 0) {           //    LED ON
        pwmWrite(led_pin, 256) ;                 //    LED 調光値設定(ON : 256)
      }                                          //
      if (strcmp(cmd,"led_off") == 0) {          //    LED OFF
        pwmWrite(led_pin, 0  ) ;                 //    LED 調光値設定(OFF : 0)
      }                                          //
      if (strcmp(cmd,"set_ledval") == 0) {       //    LED 調光値設定
        val = atoi (prm1) ;                      //    パラメータ1 を数値に変換
        pwmWrite(led_pin, val) ;                 //    LED 調光値設定
      }                                          //
      if (strcmp(cmd,"set_slidval") == 0) {      //    LED スライダー値設定
        val = atoi (prm1) ;                      //    パラメータ1 を数値に変換
        pwmWrite(led_pin, val) ;                 //    LED 調光値設定
      }                                          //
    }else{                                       // 受信失敗時
      if (errno != ENOMSG) {                     //   メッセージ無し以外は終了
        printf("msgrcv : errno = %x\n",errno) ;  //
        break ;                                  //
       }                                         //
    }                                            //
    // キーイベントを取得し、入力文字列が "exit" ならループを終了する。----------
    if (kbhit()) {                               //
      c = getchar() ;                            //  入力された文字を表示
      printf("%c",c) ;                           //
      if ( c == '\n' ) {                         //  リターン入力時
        if ( strcmp(buf,"exit") == 0 ) {         //    "exit" を入力ならループ終了
          break ;                                //
        } else {                                 //    "exit" でなければ、先頭に戻る
          p_buf = 0 ;                            // 
          buf[p_buf] = '\0' ;                    //
        }                                        //
      } else {                                   //  リターンでなければ、
        if (p_buf == 255) p_buf = 0 ;            //    バッファサイズを超える時は先頭へ
        buf[p_buf] = c ;                         //    バッファに入力文字を追加
        buf[p_buf + 1] = '\0'  ;                 //
        p_buf++ ;                                //    入力位置を +1
      }                                          //
    }                                            //
  }                                              //
                                                 //
  // メッセージキューを削除して終了 ----------------------------------------------
  errno = 0;                                     //
  if(msgctl(msqid, IPC_RMID, NULL) == -1){       //
    perror("msgctl failure");                    //
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  exit(EXIT_SUCCESS);                            //
                                                 //
}                                                //
                                                 //
                                                 //

メッセージキューに送信されたコマンドに従い、LED の値 を設定する。
本プログラムを sudo 付きで実行し、WEB から 上述のphp(html) を開いて 操作すると、スライダーに応じて LED の明るさが変わる。
端末から "exit(rtn)" を入力すると プログラムは停止する。

2020年12月5日土曜日

raspberry pi : C言語で LED 調光 (PWM 制御)

目的:

C言語で PWMを使用した LED調光を行う。

環境/構成:

PWM は 2系統あり、それぞれ割り当てることができる GPIO  は

  • PWM Channel 0 : GPIO12、GPIO18
  • PWM Channel 1 : GPIO13、GPIO19

である。

環境/構成は、C言語で LED ON/OFF と同様であるが、LED 接続回路 は 下図の通り

PWM に設定できる GPIO 4本にLED を接続。


PWM制御:

 wiringpi を使用して PWM制御を行うには、
  1. wiringPiSetupGpio で wiringpi の初期設定を行う。
    (Gpio でなくても良いが、ここでは Gpio番号を使用する前提とする。)
  2. pinMode で PWM_OUTPUT を指定する。
  3. pwmSetMode で PWM のモード (バランス/マーク・スペース) を指定する。
  4. pwmSetClock で 1レンジ当たりのクロック数を設定する。
  5. pwmSetRange で 1周期のレンジ数 (分解能) を設定する。
  6. pwmWrite で パルス幅('H' のレンジ数) を設定する。

を行う。

pinMode の設定:

pinMode (GPIO番号, PWM_OUTPUT)
でpinMode を設定する。
これを実行すると、PWMが初期状態 (バランスモード) に戻ると思われる。
( 設定した GPIO番号(channel) と異なるGPIO番号(channel) にも影響 )
この為、PWMの設定(モード,クロック,レンジ)は pinMode を設定した後に行う必要がある。

PWM のモード

PWM のモードには バランスモード とマーク・スペースモードがある。
マーク・スペースモード
一定周期で パルスが発生し、パルス幅を変化させる。
pwmSetMode(PWM_MODE_MS)
バランスモード
デューティーが 50% に近づくほど 周期が短くなる。
pwmSetMode(PWM_MODE_BAL)
モードの設定は、channel 0,1 共通。

パルス周期、パルス幅の設定

パルス周期、パルス幅の設定は、pwmSetClock, pwmSetRange, pwmWrite で行う。
パランスモードの場合、デューティー 0 (100%) の場合の周期が設定値になる模様。
ベースのクロックは 19.2MHz。
pwmSetClock(clock)
1レンジ当たりのクロック数を設定する。
1レンジの長さは (1/19.2MHz)*クロック数 となる。
クロック数の設定は、channel 0,1 共通。
pwmSetRange(range)
1周期のレンジ数(PWM周期の分解能) を設定する。
PWMの周期は レンジ数 * クロック数 * (1/19.2MHz) となる。
PWMの周波数は 19.2MHz/(レンジ数 * クロック数) となる。
レンジ数の設定は、channel 0,1 共通。
pwmWrite(GPIO,width)
GPIO番号とパルス幅(レンジ数)を設定する。
パルス幅(時間)は パルス幅(レンジ数) * クロック数 * (1/19.2MHz) となる。

pwmSetClock(40)
pwmSetRange(256)
pwmWrite(12,128)
の場合、
周波数 : 19.2/(40*256) = 0.001875MHz
= 1.875KHz
デューティ 50%

プログラム例:

C言語での PWM を使用した LED の 調光 の例を示す。
引数として、GPIO番号とパルス幅(レンジ数) を指定する。
1レンジ当たりのクロック数は 40, 1周期のレンジ数 は 256 固定。
尚、GPIO番号のチェックは行っていない。

#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>

#define LED_PIN 12

int main (int argc, char *argv[])
{
  int pin_no = 0 ;
  int num = 0 ;

  if (argc == 1) {
    pin_no = LED_PIN ;
    num = 256 ;
  } else if (argc == 2) {
    pin_no = atoi(argv[1]) ;
    num = 256 ;
  } else {
    pin_no = atoi(argv[1]) ;
    num    = atoi(argv[2]) ;
  }

    printf("pin_no : %d\n",pin_no) ;
    printf("num    : %d\n",num) ;

  wiringPiSetupGpio() ;
  pinMode (pin_no, PWM_OUTPUT) ;
  pwmSetMode(PWM_MODE_MS) ;
  pwmSetClock(40) ;
  pwmSetRange(256) ;

  pwmWrite(pin_no , num) ;

  return 0 ;
}

コンパイル 及び 実行:

コンパイルは、
gcc -o led_on led_on.c -lwiringPi

実行は、
sudo ./led_on 12 128
の様に行う。(GPIO番号 12 を デューティー 50% (パルス幅 128) で点灯)

実行すると、設定した GPIO番号に接続した LED が 点灯する。
尚、GPIO 12 と 18,  13 と 19 は 同じ PWM Channel  の為、片方の LED の 明るさを変えると もう一方の LED の明るさも変わる。
例えば、
GPIO#12 を パルス幅 128 で 点灯した後、GPIO#18 を パルス幅 64 で点灯すると、GPIO#12 の LED も GPIO#18 と 同じ明るさに変わる。

本プログラムでは、実行毎に pinMode の設定から行っているため、既に点灯(調光)したGPIO があると、後から実行した時の pinMode 設定から PWM設定完了までの間、先に点灯した GPIO の設定が変わってしまう。(一瞬の為、見ていてもわからないが、、、)
通常は先に、使用するGPIOの設定を全て行ってから、pwmWrite で パルス幅の設定のみを行うべきかと思う。

また、このプログラムの実行は sudo を付けて実行する必要がある。
sudo を付けない場合、

pinMode PWM: Unable to do this when using /dev/gpiomem. Try sudo?

の様なメッセージが表示され、実行できない。
/dev/gpiomem のパーミッション は、

crw-rw---- 1 root gpio 246, 0 12月  3 04:10 /dev/gpiomem

の様になっているが、gpio に所属しているユーザでも上のメッセージが表示された。
sudo 無しで実行できるようにしたいが、どうすれば良いか 不明。



 

2020年11月29日日曜日

raspberry pi : WEB から LED ON/OFF ( php - C言語 間通信 )

 目的:

WEB画面から raspberry pi に 接続した LED の ON/OFF を行う。
php から Cプログラム へ メッセージキュー を使用したプロセス間通信を使用する。

環境/構成:

環境/構成は、 WEB から  LED ON/OFF と同じ。 

プロセス間通信:

プロセス間通信にはいろいろな種類があるが、ここではメッセージキューを使用した通信を行い、php から Cプログラムに LED ON/OFF の指示を行う。

php から のメッセージ送信

php からメッセージを送信するには、

  1. msg_get_queue (int $key , int $permissions)
    で、指定された key でメッセージキューの作成または接続を行い、IDを取得する。
    prtmissions : 0666 (default 値) 。
  2. msg_send(SysvMessageQueue $queue ,  int $message_type ,
    string|int|float|bool $message , bool $serialize )
    で、メッセージの送信を行う。
    queue : 1. で取得した ID
    message_type : メッセージのタイプ (0 より大きな任意の数値)
    message : 送信するメッセージの本体
    serialize : ここでは FALSE を指定。(default は TRUE)

c プログラムでのメッセージ受信

  1. msgget(key_t key, int msgflg);
    で、指定された key で メッセージキューの作成または接続を行い、IDを取得する。
    msgflg : 下位9bit は permission。作成を行う場合は IPC_CREAT を指定する。
  2. msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
    で、メッセージの受信を行う。
    msgid : 1. で取得した ID
    msgp : メッセージの構造体へのポインタ
    msgsz : メッセージ構造体の中の データの最大バイト数
    msgtyp : メッセージのタイプ。0 を指定した場合は キューの最初のメッセージが読み込まれる。
    msgflg : メッセージフラグ。IPC_NOWAIT を指定した場合、キューにメッセイー時が無い場合に直ちに帰る。(errno には ENOMSG が設定)

phpファイル:

以下に、phpファイル を示す。
ここでは、key に "1111" を指定する。後述の Cプログラムの key と同じにする。
"ON", "OFF" の ボタンが押下された時、led_on, led_off の文字列をメッセージ送信する。
message_type は "1111" を指定しているが、特に意味はない。
<?php
$QKEY = 1111;
$QUEUE = msg_get_queue($QKEY, 0666);

if ($_GET['on'] == "ON") 
  msg_send($QUEUE, "1111", "led_on\0" , FALSE) ;

if ($_GET['off'] == "OFF") 
  msg_send($QUEUE, "1111", "led_off\0" , FALSE) ;
?>

<!DOCTYPE html><html lang='ja'>
  <head><meta charset='UTF-8'>
    <style>
      input {margin:8px;width:100px;}
      div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
    </style>
  
    <title> Color LED Controller </title>
  </head>
  
  <body>
    <div>
      <p>LED CONTROL</p>
      <form method='get'>
        <input type='submit' name='on' value='ON' />
        <input type='submit' name='off' value='OFF' />
      </form>
    </div>
  </body>

</html>

 

Cプログラム:

Cプログラムでは、php からの メッセージを受信し、メッセージに応じて LED の 点灯/消灯を行う。
メッセージキューの key は php と 同じ "1111" を使用する。
メッセージ受信時の msgtyp (read_type) は '0' を指定し、メッセージタイプに関わらず、先頭から受信する。
while 文で メッセージ受信をループ処理するが、同時にキーボードを監視し、"exit(rtn)"をタイプしたらプログラムを終了するようにする。キーボード入力を メッセージ受信と並行して行うためにキーイベントの取得(kbhit) を行うが、このコードは こちらのコードを使用させて頂いた。
その他説明等、コード中のコメントを参照のこと。

#include <wiringPi.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <termios.h>
#include <fcntl.h>

// *****************************************************************************
// * 定義等                                                                    *
// *****************************************************************************
// メッセージキュー 用 定義 ----------------------------------------------------
#define BUFFSIZE 256                             // バッファサイズ
#define QKEY     (key_t)1111                     // メッセージキューの key
                                                 //
struct msgbuf{                                   // メッセージの構造体
  long int type;                                 // type は long int であること。
  char data[BUFFSIZE];                           // 
};                                               //
                                                 //
// LED ON/OFF 用 定義 ----------------------------------------------------------
#define led_pin 12                               // LED を接続する GPIO #
                                                 //
// *****************************************************************************
// * キーイベントの取得                                                        *
// *****************************************************************************
                                                 //
int kbhit(void) {                                //
  struct termios oldt, newt;                     //
  int ch;                                        //
  int oldf;                                      //
                                                 //
  tcgetattr(STDIN_FILENO, &oldt);                //
  newt = oldt;                                   //
  newt.c_lflag &= ~(ICANON | ECHO);              //
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);       //
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);        //
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);  //
                                                 //
  ch = getchar();                                //
                                                 //
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);       //
  fcntl(STDIN_FILENO, F_SETFL, oldf);            //
                                                 //
  if (ch != EOF) {                               //
  ungetc(ch, stdin);                             //
  return 1;                                      //
  }                                              //
                                                 //
  return 0;                                      //
}                                                //
                                                 //
// *****************************************************************************
// * メイン 関数                                                               *
// *****************************************************************************
int main() {                                     //
  int msqid;                                     // メッセージキュー ID 
  struct msgbuf message;                         // メッセージ 
  long int read_type = 0 ;                       // リードするメッセージタイプ
  char c ;                                       // 1文字入力用
  char buf[128] ;                                // キーボード入力用のバッファ
  int  p_buf = 0 ;                               // 入力位置
                                                 //
  // メッセージキューの作成,取得 -----------------------------------------------
  //   誰でも読み書き可能なキューを作成して、ID を取得する                    --
  errno = 0;                                     //
  if( (                                          // 
        msqid = msgget(QKEY, 0666 | IPC_CREAT)   // 0666:アクセス許可パラメータ
      ) == -1 ) {                                //
    perror("msgget failure");                    //   作成失敗時の処理
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  // wiringpi の設定 -----------------------------------------------------------
  wiringPiSetupGpio() ;                          //
  pinMode (led_pin, OUTPUT) ;                    //
                                                 //
  // メッセージを受信して LED の ON/OFF を行う ---------------------------------
  while(1){
    errno = 0 ;                                  //
    if (!(msgrcv( msqid, &message, BUFFSIZE,     // メッセージの受信 
                 read_type, IPC_NOWAIT) == -1)   //
        )                                        //
    {                                            // メッセージ受信時の処理
      fprintf(stdout,"received message:\t%s\n",message.data);
      if (strcmp(message.data,"led_on") == 0) {  //
        digitalWrite (led_pin, HIGH) ;           //   LED 点灯
      }                                          //
      if (strcmp(message.data,"led_off") == 0) { //
        digitalWrite (led_pin, LOW) ;            //   LED 消灯
      }                                          //
    }else{                                       // 受信失敗時
      if (errno != ENOMSG) {                     //   メッセージ無し以外は終了
        printf("msgrcv : errno = %x\n",errno) ;  //
        break ;                                  //
       }                                         //
    }                                            //
    // キーイベントを取得し、入力文字列が "exit" ならループを終了する。----------
    if (kbhit()) {                               //
      c = getchar() ;                            //  入力された文字を表示
      printf("%c",c) ;                           //
      if ( c == '\n' ) {                         //  リターン入力時
        if ( strcmp(buf,"exit") == 0 ) {         //    "exit" を入力ならループ終了
          break ;                                //
        } else {                                 //    "exit" でなければ、先頭に戻る
          p_buf = 0 ;                            // 
          buf[p_buf] = '\0' ;                    //
        }                                        //
      } else {                                   //  リターンでなければ、
        if (p_buf == 255) p_buf = 0 ;            //    バッファサイズを超える時は先頭へ
        buf[p_buf] = c ;                         //    バッファに入力文字を追加
        buf[p_buf + 1] = '\0'  ;                 //
        p_buf++ ;                                //    入力位置を +1
      }                                          //
    }                                            //
  }                                              //
                                                 //
  // メッセージキューを削除して終了 ----------------------------------------------
  errno = 0;                                     //
  if(msgctl(msqid, IPC_RMID, NULL) == -1){       //
    perror("msgctl failure");                    //
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  exit(EXIT_SUCCESS);                            //
                                                 //
}                                                //
                                                 //
                                                 //

コンパイルは、
gcc -o ledctl  ledctl.c -lwiringPi

実行:

raspberry pi で ledctl を実行
./ledctl
し、ブラウザから、

http://"raspberry pi の アドレス"/"html のディレクトリ"/led_ctl.php

にアクセスする。(led_ctl.php は 上で格納した php ファイル)
以下の様な画面が表示される。


ON ボタン押下 で LED ON,
OFF ボタン押下で LED OFF 

する。
Cプログラムの終了は、"exit(rtn)" の入力で終了する。
尚、ctrl-C で終了した場合等、メッセージキューが残ったままになる。
コマンドラインがら、
ipcs
で メッセージキュー の状態が確認できる。
メッセージキューの削除は、
sudo ipcrm -q [msqid]
で行う。
 ( msqid は、ipcs コマンド で 確認できる )




2020年11月24日火曜日

raspberry pi : WEB から LED ON/OFF

目的:

WEB画面から raspberry pi に 接続した LED の ON/OFF を行う。

環境/構成:

WEB画面から ON/OFF を行うため、

  • WEBサーバー (apache2)
  • php

のインストールを行い、php から LED ON, LED OFF のプログラムを実行する。
LED ON, LED OFF のプログラム、LED接続回路は こちら を参照。

アプリケーションインストール:

  • WEBサーバー(apache2) のインストール
    sudo apt install apache2
    インストール完了で apache が 起動する。
    ブラウザから、http://"raspberry pi の アドレス" へアクセスすると、
    "Apache2 Debian Default Page" が表示される。
  • php のインストール
    sudo apt install php
    php -v で、php のバージョンが表示される。
    また、

    php -r "echo date('Y-m-d');" で、日付が表示される。

html ( .php) ファイルの設置:

/var/www/html の下 に html 格納用のディレクトリを作成し、以下の様な html (.php)を格納する。

<?php
if ($_GET['on'] == "ON") system('./led_on') ;
if ($_GET['off'] == "OFF") system('./led_off') ;
?>

<!DOCTYPE html><html lang='ja'>
  <head><meta charset='UTF-8'>
    <style>
      input {margin:8px;width:100px;}
      div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
    </style>

    <title> Color LED Controller </title>
  </head>

  <body>
    <div>
      <p>LED ON/OFF</p>
      <form method='get'>
        <input type='submit' name='on' value='ON' />
        <input type='submit' name='off' value='OFF' />
      </form>
    </div>
  </body>

</html>

この php では、ON ボタン の押下で ./led_on を、OFF ボタン の押下で ./led_off を実行する。

この為、php と同じディレクトリに led_on, led_off の実行ファイルを格納する。
 ( led_on, led_off の実行ファイルは こちら を参照。)
 

php 実行ユーザのグループ設定:

led_on, led_off の 実行は root で行うか、実行ユーザが gpio グループに所属している必要がある。
php の実行ユーザ ( apach2 の実行ユーザ ) は、www-data である為、 www-data に gpio グループを追加する。

sudo usermod -aG gpio www-data

www-data に 追加されたことを確認する。

groups www-data

追加されていれば、一度 raspberry pi をリブートする。

sudo reboot
 

WEB アクセスで LED ON/OFF 実行:

ブラウザから、

http://"raspberry pi の アドレス"/"html のディレクトリ"/led_ctl.php

にアクセスする。(led_ctl.php は 上で格納した php ファイル)
以下の様な画面が表示される。


ON ボタン押下 で LED ON,
OFF ボタン押下で LED OFF 

する。




2020年11月23日月曜日

raspberry pi : C言語で LED ON/OFF

 目的:

C言語で LED ON/OFF (GPIO アクセス) を 行う。

環境/構成:

本体 : raspberry pi 3B
OS : Raspberry Pi OS Lite
ライブラリ : wiringpi
インストールは、こちら を参照

LED 接続回路 : 下図の通り

LED に接続する抵抗は、
GPIO の最大電流は 16mA 。
LEDでの電圧降下分として 2V 程度とすると
R = V/I = (3.3-2)/(16^-3) = 81.25Ω
精度,誤差 等を考慮すると、
100 Ω 以上 が必用と思われる。

ここでは余裕を見て 1KΩ を使用。
(LED の仕様 (電圧降下や明るさ具合)の
 考慮が必用。
 仕様したLEDは470Ωでも結構明るかった)


プログラム:

C言語で LED の ON (GPIO 12 へ '1' ライト), OFF (GPIO 12 へ '0' ライト) を行う。
プログラムでは、

  •  include ファイル として、<wiringPi.h> が必用。
  •  初期設定として、wiringPiSetupGpio() を実行。
  •  GPIO ピンのモード設定として pinMode (GPIO番号, OUTPUT) ; を実行。
  •  GPIOへのライトは、 digitalWrite (GPIO番号, レベル (0/1) ) ; を実行。

を行う。

wiringPiSetupGpio() は、 Broadcom の GPIOピン番号で アクセスを行う場合に使用する。
代わりに wiringPiSetup() を使用すると、wiringpi 番号 (wiringpi の ピン番号)でアクセスを行う。ここでは、GPIOピン番号でアクセスするようにする。

LED ON と LED OFF の サンプルプログラムは、以下の通り。

#include <wiringPi.h>
#define led_pin 12

int main (void)
{
  wiringPiSetupGpio() ;
  pinMode (led_pin, OUTPUT) ;

  digitalWrite (led_pin, HIGH) ;

  return 0 ;
}
#include <wiringPi.h>
#define led_pin 12

int main (void)
{
  wiringPiSetupGpio() ;
  pinMode (led_pin, OUTPUT) ;

  digitalWrite (led_pin, LOW) ;

  return 0 ;
}

コンパイル:

コンパイル時、lオプションで wiringPiを指定する。

gcc -o led_on led_on.c -lwiringPi
gcc -o led_off led_off.c -lwiringPi

これで、led_on と led_off の実行ファイルができる。

実行:

wiringPiSetupGpio() は、root 権限が必用な為、コンパイルした実行ファイルを実行する場合は、sudo を付ける必用がある。
但し、gpio グループに所属していれば、sudo を付けなくても実行可能。この為、GPIOアクセスを行うユーザは gpio グループに所属していた方が便利。
尚、pi ユーザは、gpio グループに所属している。

./led_on
で LED が 点灯
./led_off
で LED が消灯
する。



raspberry pi : wiringpi を使う

 目的:

c言語 から raspberry pi の GPIO 制御を行う為、wiringpi をインストールする
 * wiringpi は 非推奨とのこと。 pigpio を使用した方が良い。
  ( pigpio 使用例 : 
C言語で LED 調光 (pigpio を使用した PWM 制御)  )

インストール:

C言語から GPIO アクセスを行うためには wireingpi を使用するのが楽の様なので、
以下の手順でインストールする。 

cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb

尚、
sudo apt install wiringpi
でもインストールできるが、現時点(2020/11/23) ではバージョンは 2.5.0 がインストールされ、このバージョンは raspberry pi 4 には 対応していない。

 コマンドライン操作:

wiringpi をインストールすると、コマンドラインから直接 GPIO アクセス可能となる。
以下に、主なコマンドを示す。

情報表示
gpio -v : バージョン表示
gpio readall : ピンの状態を表示

ピンモード設定
gpio [-g] mode <pin> out : <pin> を 出力(out)に設定
gpio [-g] mode in : <pin> を 入力(in)に設定
* -g を付加した場合、<pin> は GPIO番号。付加しない場合は wiringpi PIN番号

IO操作
gpio [-g] write <pin> 0 : <pin> に 0 ('L') を出力
gpio [-g] write <pin> 1 : <pin> に 1 ('H') を出力
gpio [-g] read <pin> : <pin> の 値を取得

その他のコマンドは、Wiringpi のページの "The GPIO Utility" を参照。

wiringpi PIN番号は、以下 (gpio readall 結果例) を参照。
wPi が wiringpi PIN番号。 BCM は GPIO番号。



2020年11月14日土曜日

raspberry pi : OS インストール(SSH, 無線LAN)

目的:

ラズベリーパイ に raspios  をインストールする。
ラズベリーパイ 用には モニタ、キーボード、マウス、有線LAN は接続せず、 Windows PC から無線LANで SSH接続して行う。

手順: 

Raspberry pi の モニタ、キーボード、マウス、有線LAN は 接続しない前提での インストール手順。
LAN は 無線LAN。
今回は、raspberry pi 3B に、Lite版 をインストール。

(1) OS ダウンロード

http://www.raspberrypi.org/downloads/
からダウンロードする。
但し、上記( 公式サイト) からのダウンロードが失敗が多い。
ミラーサイトは以下。
 (なぜか、ダウンロード先がネットワークドライブだと失敗する。 
  ローカルドライブだと成功する。)

・Raspberry Pi OS with desktop and recommended software
    http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_full_armhf/images/
  デスクトップ環境 + 公式おすすめのソフトウェア
 
・Raspberry Pi OS with desktop
    http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/
   デスクトップ環境
 
・Raspberry Pi OS Lite
    http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/
   デスクトップ環境 (X Window)  なし
 
今回は、"Raspberry Pi OS Lite" を使用。

(2) SDカードをフォーマット

SDカードを "SDFormatter" で 上書きフォーマット。

(3) OS を SDカードに書き込み

ダウンロードしたファイル を SD に書き込む。
書き込みには、balenaEtcher を使用した。
balenaEtcher は、.zip ファイルのまま書き込める。

(4) SSH ファイル を SDカードに書き込み

空のSSH ファイルを SDカードの boot ディレクトリに作成する。
Windows の エクスプローラで SDカードを開くと boot ディレクトリが表示される。
ここに、右クリックメニュー から 新規作成 > テキスト文書 を選択し、
ファイル名を SSH に変更する。 (拡張子は無し。中身は不要。ファイルサイズ 0 )

(5) wpa_supplicant.conf ファイルを SDカードに書き込み

以下の内容のファイルを SDカードの boot ディレクトリに作成する。
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
  ssid="[SSID]"
  psk="[パスフレーズ]"
  key_mgmt=WPA-PSK
  scan_ssid=1
}
[SSID], [パスフレーズ] は、各自の環境に合わせた値を設定。
"scan_ssid=1" は、SSID を非公開にしている場合に必要。

(6) Power ON

Raspberry Pi に SDカードを挿入して電源を接続し、電源onする。

(7) SSH でLOGIN

raspberry pi に SSH で LOGIN する。
IPアドレスは DHCP で割り当てられた IP アドレスで 立ち上がるため、IPアドレスは推定で指定する。
 NetEnum 等で ネットワーク上に存在する IPアドレス (ping の通ったアドレス)  を調べ、アタリをつける。
SSH 接続時の初期値は  ID : pi,  パスワード : raspberry。
SSH 接続は、Windows 上 の端末から、例えば 以下の様に 行う。

ssh pi@192.168.1.131

(7) 初期設定

raspi-config で ロケール等の 初期設定を行う。

sudo raspi-config

で、ラズベリーパイの設定を行う。
  • raspi-config の アップデート
     8 Update  を選択して Return
    で raspi-connfig 自体の アップデートを行う
  • ロケール設定
    5 Localisation Options を選択して Return。
    L1 Locale  を選択して Return。
    ja_JP.EUC-JP EUC-JP , ja_JP.UTF-8 UTF-8 で スペースキーを押下して '*' を付け、リターンキーを押下。
  • タイムゾーン設定
    5 Localisation Options を選択して Return。
    L2 Timezone  を選択して Return。
    アジア を選択してリターンキーを押下後、東京を選択してリターンキーを押下。
  • WLAN Country 設定
    5 Localisation Options を選択して Return。
    L4 WLAN Country  を選択して Return。
    JP Japan を選択してリターンキーを押下。

    Finish  を選択して Return で リブートする。

(8)ユーザ追加/パスワード設定

  1. root のパスワードを設定
    sudo passwd root
    で、root の パスワードを 設定する。
  2. 新規ユーザを設定
    通常使用するユーザを追加する。
    sudo adduser <新規ユーザ名>
    でユーザを追加する。
  3. 追加したユーザのグループを pi と同じグループにする
    pi と同じグループとする為、pi のグループを表示する。
    groups pi
    でグループが表示される。
    sudo usermod -G <pi の グループ> <新規ユーザ名>
    で、グループを追加する。
     (pi のグループは、',' 区切りで pi,adm,…… の様に 列挙する )
  4. pi ユーザのパスワードを変更する。
    piユーザのパスワードをデフォルトから変えておく。
    passwd
    で新しいパスワードを入力する。
  5. pi ユーザをリネームする。
    pi での接続を終了し、追加した新規ユーザで SSH 接続しなおす。
    ユーザ名 pi は、default のユーザ名の為、セキュリティ観点からリネームする。
    sudo usermod -l <新ユーザ名> pi

  

(9) パッケージ更新

sudo apt update
で、パッケージ管理ツールをアップデートする。
 (パッケージリストの更新)

sudo apt upgrade
で、アップグレードをする。(インストールされてるパッケージの更新)

(10) IPアドレス固定

/etc/dhcpcd.conf に以下を追記して IPアドレスを固定。
 ( /etc/dhcpcd.conf 内に 記述例があるので、それを参考に記述 )
sudo vi /etc/dhcpcd.conf
 
 

interface wlan0
static ip_address=***.***.***.***/24        // IPアドレスを指定する
static routers=***.***.***.***              // ルーターのIPアドレスを指定する
static domain_name_servers=***.***.***.***  // DNS の IPアドレスを指定する

設定後、
sudo reboot
でリブートし、設定した IPアドレスで接続できることを確認。 

(11) ホスト名変更

/etc/hostname と /etc/hosts に記載されている名前を変更し、リブートする。

sudo vi /etc/hostname
sudo vi /etc/hosts

で、それぞれ raspberrypi と書かれたところを 新しいホスト名に変更。
その後、

sudo reboot

でリブート。
この時、
sudo: ホスト raspberrypi の名前解決ができません: ホスト名にアドレスが割り当てられていません
のメッセージが発生するが、リブートする。

リブート後は、新しいホスト名となる。 

 

 

2020年8月4日火曜日

raspberry pi : NFSサーバーのインストール

目的:

NFSサーバーをインストールし 接続した USB HDD を NFS で共有できるようにする。

手順:

以下の手順で nfs-kernel-server をインストールし、共有ディレクトリの設定を行う。
  1. パッケージリストの更新、パッケージのアップデートを行う。
    sudo apt update
    sudo apt upgrade
     
    この時、カーネルの更新が行われた場合は、再起動する。
    sudo reboot
     
  2. nsf-kernel-server のインストールを行う。
    sudo apt install nfs-kernel-server
     
  3. /etc/export を編集し、共有ディレクトリを設定する。
    sudo vi /etc/exports

    以下の書式でディレクトリを追記する。
    <共有ディレクトリ> <ホスト1>(オプション) <ホスト2>(オプション) …

    例:
    /mnt/hdd1 192.168.1.0/255.255.255.0(rw,sync)

  4. 設定を反映する
    exportfs -ra

以上で、NFSサーバーのインストール、設定は終了。

クライアント側の設定については、
  Windows10の場合 はこちら
  WSL では NFS クライアント は使用できなさそう。


/etc/export 書式 :

<共有ディレクトリ> <ホスト1>(オプション) <ホスト2>(オプション) …

<共有ディレクトリ>
共有させたいディレクトリを記載
<ホスト>
共有ディレクトリにアクセスするクライアントを記載
ホスト名, IPアドレス, IPネットワーク  等を記載
IPネットワークは、
192.168.1.0/24
192.168.1.0/255.255.255.0
の様な形式。
(オプション)
主なオプションを以下に示す。
rw             : 読み出し、書き込み 可能
ro             : 読み出し専用 (default)
sync           : 同期書き込みを有効にする (default)
async          : 非同期書き込み(遅延書き込み)を有効にする
root_squash    : root としての書き込みを行わない様にする。(default)
                 (rootのuidとgidをanonymousのuidとgidに割り当てる。)
no_root_squash : root_squashを無効にする。
all_squash     : すべてのuidとgidをanonymousのuidとgidに割り当てる。
anonuid=uid    : anonymousに割り当てるuidを指定する。
anongid=gid    : anonymousに割り当てるgidを指定する。
secure         : 1023番以前のポートの接続のみ許可する。 (default)
insecure       : 1024番以降のポートの接続も許可する。


Windows10 : NFSクライアントのインストール

目的:

Windows10 に NFSクライアント をインストールし、Linux に接続した USB HDD を NFS で共有できるようにする。

手順:

以下の手順で NFSクライアント を有効化し、NFS アクセスの設定を行う。
  1. NFS クライアントの有効化
    1. スタート(画面左下) を右クリックし、「アプリと機能」を押下
    2. 右上 関連設定 の 「プログラムと機能」を押下
    3. 左側にある 「Windowsの機能の有効化または無効化」を押下
    4. 「NFS用サービス」の 「NFSクライアント」にチェックをして、「OK」を押下
       
  2. マウント
    1. スタート(画面左下) を右クリックし、「コマンドプロンプト」を押下
      (管理者権限ではない方)
    2. mount <NFSサーバ>:<exportディレクトリ> <マウントドライブ>
      で、NFSサーバーのディレクトリをマウントする。
      例:
      mount 192.168.1.91:/mnt/hdd1 w:¥

  3. アンマウント
    1. umount <マウントドライブ>
      例:
      umount w:¥

アクセス時の uid, gid:

マウント時の uid, gid を指定するには、¥Windows¥System32¥drivers¥etc ディレクトリに passwd ファイル, group ファイルを 作成する必要がある。
作成しない場合の uid, gid は 適当な値(?) になっている。
uid, gid の指定は、以下の様な ファイルを作成して行う。

uid :

¥Windows¥System32¥drivers¥etc¥passwd
に、
<Windows ユーザ名>:x:<uid>:<gid>:<コメント>::
の形式で記入する。
例: (Windows ユーザ名=hoge, uid=1001, gid=1001 の場合)
hoge:x:1001:100:hoge::

gid :

¥Windows¥System32¥drivers¥etc¥group
に、
<Windows 所属グループ名>:x:<gid>:
の形式で記入する。
例: (Windows ユーザ名=Administrators, gid=1001 の場合)
BUILTIN¥Administrators:x:1001:
( Administrators の場合は、前に BUILTIN¥ を付ける )

passwd, group ファイルを作成/保存したら、内容を反映させる為に 一度 アンマウント して、再度 マウント を行う。

以上

2020年5月10日日曜日

raspberry pi : 無線LAN設定

目的:
無線LAN(WiFi) を使用できるようにする。

概要:

手順:
  1. 無線LAN I/F の確認
    $ ifconfig
    で、wlan0 等 の 無線LAN I/F が存在することを確認。
     
  2.  SSID, パスフレーズ(PSK:事前共有キー) を設定する。
    $ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf
    で、wpa_supplicant.conf に 以下の様に SSID, パスフレーズを設定する。

    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
    update_config=1
    country=JP
    
    network={
      ssid="[SSID]"
      psk="[パスフレーズ]"
      key_mgmt=WPA-PSK
      scan_ssid=1
    }
    

    [SSID], [パスフレーズ] は、各自の環境に合わせた値を設定。
    "scan_ssid=1" は、SSID を非公開にしている場合に必要。
     
    psk を 暗号化 (256bit ハッシュ化) したい場合は、
    $ wpa_passphrase [SSID] [パスフレーズ]
    で 暗号化されたpsk値をを取得する。
    $ wpa_passphrase SSID PASSPHRASE
    network={
            ssid="SSID"
            #psk="PASSPHRASE"
            psk=38497220976092fc2707a838e4d4385019256149f99f935be22c90159d3b8373
    }
    

    取得できた psk値 を "[パスフレーズ]" の代わりに設定する。

    $ sudo reboot
    でリブートすると、DHCP により IPアドレスが設定される。
    ( ifconfig で確認する )
       
  3.  固定IP 設定
    $ sudo vi /etc/dhcpcd.conf
    で、固定IP 等を設定する。
    設定は 有線LAN と同様に設定する。
    # 有線LAN  IPアドレス設定
    interface eth0
    static ip_address=192.168.1.90/24
    #static ip6_address=fd51:42f8:caae:d92e::ff/64
    static routers=192.168.1.1
    static domain_name_servers=192.168.1.91 8.8.8.8 fd51:42f8:caae:d92e::1
    
    # 無線LAN  IPアドレス設定
    interface wlan0
    static ip_address=192.168.1.120/24
    static routers=192.168.1.1
    static domain_name_servers=192.168.1.91 8.8.8.8 fd51:42f8:caae:d92e::1
    

2020年4月17日金曜日

raspberry pi : スマホ(android) から Samba のファイルが見えない

現象:

スマホ(android)にインストールした X-Plore から Samba のファイルが見えない

対処:

X-Plore に設定した Raspberry Pi 4 への ユーザ名を削除することでファイルが見える様になった。

状況:

スマホにインストールした X-Plore から Raspberry Pi 4 に入れた Samba (V. 4.9.5) のファイルが見えない。
 ( ディレクトリは見えるが、中を見れない )
Windows10 からは 問題なくファイルにアクセス可能。

Raspberry Pi 3 の samba (V.  4.2.14) は アクセスできている。
設定は、同様の設定。(と思っている)

X-Plore の 表示では、
 Raspberry Pi 4 : SMB1
 Raspberry Pi 3 : SMBv2
となっている。

Log ( /var/log/samba/log. ) を確認したところ、 " Bad SMB2 signature for message" のメッセージがある。
また、( /var/log/samba/log.[IPアドレス] ) を確認すると、"No such user (ユーザ名) [?] - using guest account"のメッセージがある。

X-Plore に設定していた Raspberry Pi 4への ユーザ名 を消したところ、ファイルが見えるようになった。

何が悪いのか 不明。
設定が悪いのか ?,   X-Plore の 問題か ?,  samba の 問題か ?

2020年4月16日木曜日

raspberry pi : VPNサーバーのインストール

目的:
自宅外から自宅のネットワークにアクセスできるようにする。
 
概要:
VPNサーバーとして Softether をインストールし、VPN接続で 自宅外から SSH接続やネットワークドライブ(samba) へのアクセスを行えるようにする。


手順:
  1. bridge-utils のインストール
    VPN接続でVPNサーバー自身(VPNサーバーをインストールした raspberry pi) にアクセスできるようにする為、仮想ブリッジを経由して物理NICアクセスする必要がある。
    1. bridge-utils をインストールする
      $ sudo apt install bridge-utils
       
    2.  /etc/network/interfaces に設定を追加
      $ sudo vi /etc/network/interfaces
      auto br0
      iface br0 inet manual
      bridge_ports eth0      <--- ブリッジ接続するポートを設定
      bridge_maxwait 10
      
       
    3. dhcpcd.conf でIPアドレスを設定する。
      $ sudo vi /etc/dhcpcd.conf
      denyinterfaces eth0
      
      interface br0
      static ip_address=192.168.1.91/24
      static routers=192.168.1.1
      static domain_name_servers=192.168.1.1 8.8.8.8
      
      ブリッジ(br0) に IPアドレス等を設定する。
      ブリッジ接続するポート(eth0) の 設定は削除(コメントアウト) し、
      denyinterfaces で DHCP によるIPアドレスの割り当てが無いようにする。
      denyinterfaces の 設定は、ポートの設定(他ポートも含む)よりも前に記述する。
        
    4.  リブートする
      $ sudo reboot
      リブートして、ifconfig 等で設定を確認する。
       
     
  2.  SoftEther のインストール
    1. SoftEther ソフトウェアの URL 確認 (WEBブラウザで確認)
      SoftEtherダウンロードセンター
      にアクセスする。
       「コンポーネントを選択」で 「SoftEther VPN Server」 を選択
       「プラットフォームを選択」で 「Linux」を選択
       「CPU を選択」 で 「ARM EABI (32bit)」を選択
       最新版のダウンロードファイルのURL を取得する。
        ( 右クリック して リンクのアドレス(URL)を コピーする )
       
    2. SoftEther ソフトウェアをダウンロードし、解凍する。
      以降は root で作業を行う。
      任意のディレクトリで、
      $ su
      # wget [取得した URL]
      # tar zxvf [ダウンロードしたファイル名]
          --> vpnserver ディレクトリができる。
       
    3. Make を実行
      vpnserver ディレクトリに移動して make を実行する。
      # cd vpnserver
      # make
          --> licence agreement を読み (1を選択)、同意 (1を入力) する。
          ( Ver 4.38 では 入力の要求は無かった。 2021.09/25 )
       
    4. vpnserverディレクトリを /usr/local に移動する。
      # cd ..
      # mv vpnserver /usr/local/
       
    5. パーミッションを変更
      # cd /usr/local/vpnserver
      # chmod 600 *
      # chmod 700 vpncmd
      # chmod 700 vpnserver
       
    6. 自動起動のサービスを作成する
      # vi /etc/systemd/system/vpnserver.service
      [Unit]
      Description=SoftEther VPN Server
      After=network.target network-online.target
      
      [Service]
      User=root
      ExecStart=/usr/local/vpnserver/vpnserver start
      ExecStop=/usr/local/vpnserver/vpnserver stop
      Type=forking
      RestartSec=3s
      WorkingDirectory=/usr/local/vpnserver/
      #ExecStartPost=/bin/sleep 10 ; brctl addif br0 tap_vlan
      
      [Install]
      WantedBy=multi-user.target
      
      コメントアウトした行は、管理マネージャで tap を設定した後、コメントアウトを解除する。
        
    7. サービスを起動する
      # systemctl start vpnserver

      起動確認
      # systemctl status vpnserver.service
       
    8. 自動起動を有効にする
      # systemctl enable vpnserver.service
       
    9. リブートして、サービスを確認する
      # reboot
      $ sudo systemctl status vpnserver.service
       
  3. 管理マネージャーの設定
    1. Windows PC に管理ソフトウェアをインストールする。
      SoftEtherダウンロードセンター
      にアクセスする。
       「コンポーネントを選択」で
         「SoftEther VPN Server Manager for Windows」 を選択
       「プラットフォームを選択」で
         「Windows (.Zip package without installeers)」を選択
      ダウンロードしたファイルを解凍し、vpnsmgr.exe を起動する。
       
    2. SoftEther VPN Server への接続設定
      「新しい接続設定」をクリック
      「接続設定名」 に接続先の 任意の名前を設定
      「ホスト名」 に SoftEther VPN Server をインストールした raspberry pi のIPアドレスを設定
      「ポート番号」に 443 を設定
      「OK」 を押下
       
    3. SoftEtheer VPN Server へ接続
      「接続」をクリック
      管理者のパスワード設定ダイアログが開くので、パスワードを設定。
       
    4. 簡易セットアップ
      SoftRther VPN Server / Bridge 簡易セットアップ ダイアログが開くので以下を設定。
      「リモートアクセス VPN サーバー」にチェックして 「次へ」を押下
      「はい」を押下
      「仮想 HUB 名」を入力し、「OK」を押下。(Default は VPN)
      「ダイナミック DNS ホスト名の変更」に任意の名前を設定し「閉じる」を押下
      「L2TP over IPsec」 にチェックし、上で入力した仮想HUB名を選択。
       事前共有鍵(9文字以内推奨)を決めてOKをクリックする。
      「VPN Azure 無効にする」を選択して「OK」 を押下。
      「VPN 接続を受け入れるためのユーザーの作成」で、「ユーザを作成する」を押下。
      「ユーザー名」に任意の名前 を入力、
      「認証方法」にパスワード認証 を選択、
      「パスワード認証」にパスワード を設定して 「OK」を押下
       確認画面で OK を押下する。
       作成したユーザ名が表示されたら、閉じるを押下する。
      「ローカルブリッジの設定」で、raspberry pi の LAN のポート名 (eth0 等)を選択して 閉じる を押下。
       
    5. ローカルブリッジの設定
      「ローカルブリッジ設定」を押下
       上で設定した仮想HUB を選択して、「ローカルブリッジの削除」を押下
      「新しいローカルブリッジの定義」で
       「仮想HUB名」を入力。(例えば VPN)
       「作成する種類」で 「新しいtapデバイスとのブリッジ接続」を選択
       「新しいtapデバイス名」を設定。(例えば、vlan)
       「ローカルブリッジを追加」を押下。
      「閉じる」を押下
      「暗号化と通信関係の設定」を押下
      「暗号化アルゴリズム名」を「DHE-RSA-AES256-SHA」に変更して「OK」を押下
       
    6. 自動起動のサービスの修正
      $ sudo vi /etc/systemd/system/vpnserver.service 
      自動起動サービスの コメントを外す。
      ローカルブリッジの設定で 「新しいtapデバイス名」を vlan 以外に設定した場合は、”tap_vlan" を "tap_[新しいtapデバイス名]” に変更する。
    7. raspberry pi をリブートする
      管理マネージャを閉じ、raspberry pi をリブートし、tap が ブリッジされている事を確認する。
      $ sudo reboot
      $ brctl show br0
      bridge name    bridge id             STP enabled    interfaces
      br0            8000.5ea8b6f10493     no             eth0
                                                          tap_vlan
      
       
  4. ルータ設定
    ルータのポートマッピングで、500/UDP, 4500/UDP を ラズベリーパイのIPアドレスにマッピングする。
    設定方法は、各ルータのマニュアルを参照。
     
  5. ファイアウォール解放
    ラズベリーパイのファイアウォール設定で、500/UDP, 4500/UDP を通過させるように設定する。
    sudo ufw allow 500/udp
    sudo ufw allow 4500/udp
     
  6. 通信確認
    スマホ等からVPN 接続できることを確認する。
    ・android の場合の例 (4G 等で接続)
    設定 - ネットワークとインターネット - VPN
    で、右上の + をクリックし、VPNプロファイルの編集を行う。
    (機種 や android バージョンによって 異なるかも)
     名前       : 任意の名前
     タイプ     :L2TP/IPSec PSK
     サーバーアドレス:ダイナミック DNS ホスト名 に設定した名前
     IPSec事前共有鍵 :設定した 事前共有鍵
     ユーザ名    :設定した ユーザ名
     パスワード   :設定した パスワード
    等を設定して保存後、接続できる事を確認する。
    (スマホは、4G 等の異なるネットワーク で接続していること。)

    ・Windows10 の場合の例 (テザリング等で接続)
    設定 - ネットワークとインターネット - VPN
    で、 +(VPN接続を追加する) をクリックし、VPN接続を追加する。
     VPNプロバイダー    :Windows(ビルトイン)
     接続名          : 任意の名前
     サーバー名またはアドレス:ダイナミック DNS ホスト名 に設定した名前
     VPNの種類       :事前共有キーを使ったL2TP/Ipsec
     事前共有キー      :設定した 事前共有鍵
     サインイン情報の種類  :ユーザー名とパスワード
     ユーザ名        :設定した ユーザ名
     パスワード       :設定した パスワード
    等を設定し、接続できる事を確認する。
    (Windows は、テザリング等 の異なるネットワーク で接続していること。)
     
  7. LOG の所在
    VPNサーバーインストールディレクトリ下に log ディレクトリがある。
    接続できない場合等、server_log ディレクトリ内の log を確認して原因調査を行う。

    /usr/local/vpnserver/server_log/vpn_********.log

2020年1月17日金曜日

linux : サービスの作成、管理

目的:

Linux での サービスの作成、管理について記しておく。

概要:

サービスの作成、管理は systemctl で行う。
systemctl は rootで実行, または sudo をつけて実行する。
サービスは、"unit" 単位で管理される。

systemctl コマンド:


  • サービス起動
    $ sudo systemctl start [unit名]
  • サービス停止
    $ sudo systemctl stop [unit名]
  • サービス再起動
    $ sudo systemctl restart [unit名]
  • サービスリロード(再読み込み)
    $ sudo systemctl reload [unit名]
  • サービスステータス表示
    $ sudo systemctl status [unit名]
  • サービス自動起動有効
    $ sudo systemctl enable [unit名]
  • サービス自動起動無効
    $ sudo systemctl disable [unit名]
  • サービス自動起動設定確認
    $ sudo systemctl is-enabled [unit名]
  • サービス一覧
    $ sudo systemctl list-unit-files --type=service
  • 設定ファイルの再読込
    $ sudo systemctl daemon-reload

サービスの作成:

  1. サービスで実行する処理(スクリプト等)を作成する。
  2. /etc/systemd/system に unit定義ファイル (下記参照) を作成する。
  3.  sudo systemctl list-unit-files --type=service で作成したサービスが表示されることを確認する。
  4.  サービスを起動する。(systemctl start [unit名])
  5. 自動起動を設定する。(systemctl enable [unit名])

unit定義ファイル:

unit定義ファイルの例

[Unit]
# サービスの説明。内容は任意
Description=unit file sample
# このUnitより先に起動するべきUnitを設定
After=network.target
 
[Service]
# 実行するコマンドやスクリプトを記述
ExecStart=/usr/bin/test.sh
# サービス停止時の Kill する単位を設定
KillMode=process
# プロセスの起動方法を指定
Type=simple
# サービス停止時の再起動条件 (no は再起動しない)
Restart=no

[Install]
# 該当ユニットへの弱い依存関係を設定
WantedBy=multi-user.target

log 確認:


サービスの log確認は、
$ sudo journalctl -u [unit名]

で行う。
このlog は、/var/run/log/journal にバイナリ形式で保存され、再起動で消えるため、 log は直近の起動後のみが確認できる。
再起動で消えないようにする為には、 /var/log に journal ディレクトリを作成し、再起動する。

$ sudo mkdir /var/log/journal

$ sudo reboot

2019年12月31日火曜日

raspberry pi : wordpress サイトの移行

目的:

raspberry pi 3 の wordpress のサイトを raspberry pi 4 に移行する。

手順:

wordpress のインストールは済んだ状態で移行作業を開始。
  1. プラグイン 「All-in-One WP Migration」のインストール
    両方の raspberry pi の wordpress に   プラグイン 「All-in-One WP Migration」 をインストール、有効化する。
     
  2. 旧 wordpress のエクスポート
    1. 旧 wordpress (raspberry pi 3) で 管理画面の左メニューから「All-in-One WP Migration」→「エクスポート」を選択。
    2. "エクスポート先" から "ファイル" を選択。
    3. 準備終了後、"***** をダウンロード" を押下してファイルを保存する。
       
  3. rapsberry pi 4 の 最大アップロードファイルサイズを大きくする。
    1. .htaccessを有効にする。
      $ sudo vi /etc/apache2/apache2.conf
      で  <Directory /var/www/> セクションの
      AllowOverride None  を
      AllowOverride All    に変更。
       
    2. .htaccess に 最大アップロードファイルサイズの設定を行う。
      $ sudo vi /var/www/html/wordpress/.htaccess
      /var/www/html/wordpress/.htaccess に 以下を追記。
    3. php_value upload_max_filesize 128M
      php_value post_max_size 128M
      php_value memory_limit 256M
      php_value max_execution_time 300
      php_value max_input_time 300
      

  4.  apache2 を再起動する。
    $ sudo /etc/init.d/apache2 restart

     
  5. 新 wordpress にインポートする。
    新 wordpress (raspberry pi 4) で  管理画面の左メニューから「All-in-One WP Migration」→「インポート」を選択。
    最大アップロードサイズが設定通りであることを確認。
    ダウンロードしたファイルをドラッグアンドドロップすると、インポートが開始される。

2019年12月30日月曜日

raspberry pi : WEBサーバ (apache, wordpress 他) の インストール

目的:

WEBサーバを立てる。
当面、宅内のローカルWEBサーバとする。

手順:

WEBサーバ として、apache, PHP, mySQL, workpress をインストールする。
  1. apache のインストール
    • apache2 のインストール
      $ sudo apt install apache2
      別PC から http://[ラズベリーパイのIPアドレス] で、
      Apache2 Debian Default Page
      It works!
      とかの表示がでれば、OK
    •  apache2 のグループを自IDに追加
        自分のグループに www-data を追加しておく。
      $ sudo gpasswd -a [自ユーザ名] www-data
    • エラー発生時のバージョン情報等を表示させなくする
      エラー発生時等に、apacheバージョン,サーバー名等を表示させない様にしておく。
      $ sudo vi /etc/apache2/conf-available/security.conf
      を以下の通り編集する。
      (全サイトにて起用する場合。個別サイトでの対応時は、別ファイル)
      ServerSignature Off    <=== コメントアウトを外す
      #ServerSignature On    <=== コメントアウトする
      

  2. webサーバーのルート、設定ファイル等
    • 設定ファイルの所在
      apach2 全体の 設定ファイルは、
      /etc/apache2/apache2.conf
      サイトの設定ファイルは、
      /etc/apache2/sites-available
      にある。ここには、複数の .conf があるが、
      /etc/apache2/sites-enabled
      にリンクされたファイルが有効なファイル。
      初期状態では、000-default.conf が リンクされている。
    • /etc/apache2/sites-enabled への リンク/リンク解除のコマンド
      リンク/リンク解除のコマンドは、
      $ sudo a2ensite     //リンクを張る
      $ sudo a2dissite    //リンク解除
       
    • ドキュメントルート
      sites-enabled に リンクされた .conf に webサーバーのルート(ドキュメントルート)が設定されている。
      例えば、
      DocumentRoot /var/www/html
      が、webサーバーのルート。

      http://[ラズベリーパイのIPアドレス] で表示されるのは、
      /var/www/html/index.html
      の内容。初期状態では、”Apache2 Debian Default Page” が表示される。
      必要に応じて、index.html を書き換える。
       
  3. PHP7.3 インストール
    $ sudo apt install php7.3
     
  4. PHP7.3-mysql インストール
    $ sudo apt install php7.3-mysql
     
  5. MariaDB インストール
    $ sudo apt install mariadb-server
     
  6. MariaDB 初期設定
    $ sudo systemctl start mariadb.service
    $ sudo /usr/bin/mysql_secure_installation

    Enter current password for root (enter for none):
     のメッセージは、初期状態では未設定の為 Enter (空打ち)。

    Set root password? [Y/n]
     は Y で、root のパスワードを入力する。

    その他の入力は Y を入力。
     
  7. phpmyadmin インストール
    $ sudo apt install phpmyadmin

    自動再設定をする web サーバ:
     apache2 を選択

    phpmyadmin 用のデータベースを dbconfig-common で設定しますか?
     はい を選択

    phpmyadmin 用の MySQL アプリケーションパスワード:
     MariaDB に設定したパスワードと同じパスワードを設定
     
    apacheに設定を読ませる為、/etc/apache2/apache2.conf を修正
    $ sudo vi /etc/apache2/apache2.conf
    最下行に次の記述を追加。
    Include /etc/phpmyadmin/apache.conf
     
    
  8. MariaDB に ユーザを登録
    phpmyadmin でアクセスする場合、root で ログイン しようとすると、
    #1698 - Access denied for user 'root'@'localhost'
    となる。この為、新しいユーザを登録する。(参考)
    $ sudo mysql -u root
     で MariaDBに接続。
    CREATE USER 'hoge'@'localhost' IDENTIFIED BY 'hogepasswd';
     で ユーザを追加。
    GRANT ALL ON *.* TO 'hoge'@'localhost' WITH GRANT OPTION;
     で 管理者用権限 を 付与する。
    \q で MariaDB から抜ける。
     
  9. 起動確認
    apache2 を再起動する。
    $ sudo /etc/init.d/apache2 restart
    再起動後、 http://[ラズベリーパイの IPアドレス]/phpmyadmin/ にアクセスし、
    ログイン画面が表示されることを確認する。
    追加した ユーザで ログインができることを確認する。
    画面左上のアイコンの 左から2番目のアイコン(ログアウト) を押下して抜ける。
     
  10. phpMyAdmin セキュリティ対策
    将来サーバーを公開した場合等、phpMyAdmin が攻撃対象となる可能性がある為、
    対策が必要。対策として、以下を実施。
    1. エイリアスの変更。
      /etc/phpmyadmin/apache.conf
      の 3行目のエイリアス設定を変更し、phpmyadmin とは異なる名称にする。
      $ sudo vi /etc/phpmyadmin/apache.conf
      (変更前)  Alias /phpmyadmin /usr/share/phpmyadmin
      (変更後)  Alias /[新しい名前]    /usr/share/phpmyadmin
      変更後、apache2 を再起動する。
      $ sudo /etc/init.d/apache2 restart

      今後、phpmyadmin にアクセスする場合は、
       http://[ラズベリーパイの IPアドレス]/[Ailias に設定した名前]/
      で行う。
       
    2. ローカルLAN内からのアクセスに限定する。
      自宅内からのアクセスに限定できる場合は、以下の設定を行い、特定のIPからのアクセスからしか受け付けないようにする。
      $ sudo vi /etc/phpmyadmin/apache.conf
      /etc/phpmyadmin/apache.conf の 8行目あたり ( <Directory /usr/share/phpmyadmin> セクション ) に、以下を追加する。
      Order Deny,Allow
      Deny from All
      Allow from 192.168.1.
      
       
  11. wordpress インストール
    1. wordpress 用データベース設定
      phpMyAdmin にログインして、データベースを設定
      データベースタブから、”データベースを作成する” で作成。
      例えば、データベース名 に wordpress を入力して "作成" を押下。
       (まだ、テーブルは無い)
      特権タブ を選択し、"wordpress" からのアクセス用ユーザーを追加する。
      "Add user account" を押下し、
      ユーザー名、パスワードを入力し、
      ”パスワードを生成する" で "生成する" を押下して生成されたパスワードを控え、
      実行を押下。
    2. wordpress をダウンロード
      /var/www/html で、パッケージを取得し、解凍する。
      $ cd /var/www/html
      $ sudo wget http://wordpress.org/latest.tar.gz
      $ sudo tar xzf latest.tar.gz
      $ sudo rm -rf latest.tar.gz
      $ sudo chown -R www-data:www-data /var/www/html/wordpress

      最後にリブートする。
      $ sudo reboot  
       
  12. wordpress 設定
    http://[ラズベリーパイの IPアドレス]/wordpress/
    にアクセスすると設定画面となる。
    日本語を選択して "続ける"
    "さあ、始めましょう!" を押下。
    データベース名、ユーザ名、パスワードに 上(11) で設定した値を入力。
    その他は初期状態のまま、"送信"
    "インストール実行" を押下。
    サイトのタイトル、ユーザ名、パスワード、メールアドレス を入力し、"wordpressをインストール"を押下。
    "ログイン" を押下し、設定したユーザ名、パスワードを入力すると、"ダッシュボード" が表示される。
    以上の設定は、
    /var/www/html/wordpress/wp-config.php
    で 修正できる。
     
    尚、この後は
    http://[ラズベリーパイの IPアドレス]/wordpress
    にアクセスすると サイトが表示される。
    管理画面は、
    http://[ラズベリーパイの IPアドレス]/wordpress/wp-login.php
    で ログイン できる。