工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

nmcliで、複数の無線ネットワーク設定のうち、システム起動時に特定のネットワーク設定を接続させる

概要

nmcliで、複数の無線ネットワーク設定のうち、システム起動時に特定のネットワーク設定を接続させることができた。


背景と目的

あるシステムで、複数の無線ネットワークが利用可能な環境で、起動時には特定のネットワークに接続し、その後アプリケーション側で他のネットワークへ切り替えたかったのでその方法を調べて試す。


詳細

1.実施環境

nmcliでネットワーク設定を複数定義している。ここでは2つあるとしてそれぞれ設定A、設定Bとし、起動時にAを、そのあとアプリケーション側の任意のタイミングでBに切り替えたいとする。


2. 調査

nmcliで設定できる項目として、起動時の自動接続に関係ありそうなものを見てみると、

$ nmcli c show 設定A
:
connection.autoconnect:                 yes
connection.autoconnect-priority:        0
:

というものがあった。こちらを参考にすると、

  • connection.autoconnectは、まさに自動接続の可否
  • connection.autoconnect-priorityは、複数接続可能なものがあった場合の優先度

ということなので、設定Aのconnection.autoconnectを yes、設定Bのconnection.autoconnectをnoに設定してやればよいということになる。


3.試す

現状は両方autoconnectがyesであり、いつも設定Bにつながってしまう状態。で、以下を実行。

nmcli c mod 設定A connection.autoconnect yes
nmcli c mod 設定B connection.autoconnect no

システムを再起動したところ、設定Aのネットワークにつながった。ということで、目的は達成。

なお、両方yesのままconnection.autoconnect-priorityを変えてみた。数値が大きいほうが優先ということなので、設定Aの数値を大きくしたが、設定Bにつながってしまい、うまくいかなかった。なぜ???


まとめと今後の課題

nmcliで、複数の無線ネットワーク設定のうち、システム起動時に特定のネットワーク設定を接続させることができた。

Wi-Fiアクセスポイントにする

概要

RaspberryPiをWi-Fiアクセスポイントにするときにちょっとハマったので、メモ。


背景と目的

RaspberryPiをWi-Fiアクセスポイントで動かそうと思い、適当にやったら意外とハマってしまったので、次回ハマらないようにメモしておく。


詳細

0.実施条件およびやりたいこと

  • Raspberry Pi 3 Model B
  • Raspbian Stretch
  • Raspberry PiWi-Fiアクセスポイントとして動作させたい
  • 手元のタブレットをこのアクセスポイントに接続させ、Raspberry Pi上にあるローカルWebサーバ上のコンテンツを表示させたい
  • IPアドレスは固定したい
  • Ethernetはつながない、インターネットへの接続はできなくてもよい


1.関連ソフトインストール

いきなり、apt-get install ... と行きたいところだが、そもそもアクセスポイントとして動くために何が必要かというと、

  • アクセスポイント化するソフト
    • アクセスポイント化するソフトは絶対必要なのは言うまでもない。hostapdというソフトがネット上でよく例に上がってくるので、それを使う。
  • DHCPクライアント
    • 自分がアクセスポイントであっても、IPアドレスDHCPサーバに振ってもらわないといけないので必要(自動、固定の場合ともに)。だが、これは通常Wi-Fiアクセスポイントに接続する場合にはRaspberry Piが振られる側なので、dhcpcdというソフトがもともと入っている。インストール必要なし。
  • DHCPサーバ
    • これは、自分がアクセスポイントになったときに、接続してきた相手にIPアドレスを振ってあげないと通信できないので、必要。いろいろあるようだが、isc-dhcp-serverというのが代表的に使われているようなので、それを使う。

というわけで、

sudo apt-get update
sudo apt-get install hostapd
sudo apt-get install isc-dhcp-server
sudo apt-get install rng-tools

最後のrng-toolsは、やってみて必要なのが分かったので、書いておく。これがないと、hostapdがうまく動かない。/dev/random関連でエラーが出る。


2.Wi-Fiクライアントとしての設定を無効化

現在、自宅のWi-Fiにクライアントとして接続しているが、これを無効化する。

2.1 wpa_supplicantを止める

sudo systemctl stop wpa_supplicant
sudo systemctl disable wpa_supplicant

なお、wpa_supplicant.confはwpa_supplicant自体が止まり参照されなくなるので、そのままでよい。


2.2 dhcpcdの設定を固定IPに変える

IPアドレス固定で使いたいので、現在のクライアントモードの設定をバックアップしてから編集する。

sudo cp /etc/dhcpcd.conf /etc/dhcpcd.conf.client
  • /etc/dhcpcd.conf
denyinterfaces wlan0
interface wlan0
static ip_address=192.168.2.167/24

アクセスポイントモードの設定も、後で戻せるようにバックアップ。

sudo cp /etc/dhcpcd.conf /etc/dhcpcd.conf.apmode

編集したら再起動。

sudo systemctl restart dhcpcd

ここで、もしも

Job for dhcpcd.service failed because the control process exited with error code.
See "systemctl status dhcpcd.service" and "journalctl -xe" for details.

と出る場合は、

sudo systemctl status dhcpcd

で、ログを見て

Not running dhcpcd because /etc/network/interfaces
 defines some interfaces that will use a
 DHCP client or static address

と出ている場合は、/etc/network/interfacesの設定がまずいので、以下の2行をコメントアウトしてから再度実行。

#auto wlan0
#iface wlan0 inet dhcp


3.hostapdの設定

/etc/hostapd/hostapd.confを作成し以下を記入。ただし、ここは環境により違うので、うまくいかなかったら適宜設定を変える。(私の環境の場合、以下でとりあえずうまくいっている)

interface=wlan0
driver=nl80211
hw_mode=g
channel=3
ssid=SSID名
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_passphrase=パスフレーズ
rsn_pairwise=CCMP

hostapdをデーモンとして動かすときに上記ファイルを読むように、/etc/default/hostapdの下記部分を編集。

DAEMON_CONF="/etc/hostapd/hostapd.conf"

デーモンを有効化。

sudo systemctl unmask hostapd 
sudo systemctl enable hostapd
sudo systemctl start hostapd


4.isc-dhcp-serverの設定

/etc/dhcp/dhcpd.confを編集。それにしても、dhcpcdとdhcpdはめちゃくちゃ紛らわしい。。。今回固定したいアドレスを192.168.2.167とすると、rangeをそれが入る範囲とする。

sudo cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.original
subnet 192.168.2.0 netmask 255.255.255.0 {
  range 192.168.2.100 192.168.2.200;
  option broadcast-address 192.168.2.255;
  default-lease-time 600;
  max-lease-time 7200;
}
sudo cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.apmode

デーモンを起動。

sudo systemctl enable isc-dhcp-server
sudo systemctl restart isc-dhcp-server # すでに起動しているかもしれないので

ここまでで、自分に固定IPアドレスが振られて、SSIDを吹いているはず。クライアントを接続させて、クライアントにもIPアドレスが振られればOK。自分にIPアドレスが振られていない場合は、DHCPクライアントの設定、クライアントに振られていない場合はDHCPサーバの設定がまずいかもしれない。 SSIDを吹いているのに、接続できなかったりする場合は、hostapd.confがだめかもしれない。私はこれで結構ハマった。結局どうすればいいのか、はっきりわからないが、動いてしまったのでよしとする。。。


5. アクセスポイントモードに一気に変更

上記を一度はやったという前提で、一気にアクセスポイントモードに変えるには以下。

sudo systemctl stop wpa_supplicant
sudo systemctl disable wpa_supplicant
sudo cp /etc/dhcpcd.conf.apmode /etc/dhcpcd.conf
sudo systemctl restart dhcpcd
sudo systemctl enable rng-tools
sudo systemctl restart rng-tools
sudo systemctl enable hostapd
sudo systemctl restart hostapd
sudo systemctl enable isc-dhcp-server
sudo systemctl restart isc-dhcp-server


6. クライアントモードに戻す

逆に戻すには、各種サービスを切り替えればよい。

sudo systemctl stop isc-dhcp-server
sudo systemctl disable isc-dhcp-server
sudo systemctl stop hostapd
sudo systemctl disable hostapd
sudo cp /etc/dhcpcd.conf.client /etc/dhcpcd.conf
sudo systemctl restart dhcpcd
sudo systemctl enable wpa_supplicant
sudo systemctl restart wpa_supplicant


まとめと今後の課題

Raspberry PiWi-Fiアクセスポイントにすることができた。実際にやってみたら結構ハマってしまったのでなめてかからないほうがよいと思った。


WebViewを使ってWebアプリを表示させるアプリを作った時にやったことメモ

概要

WebViewを使ってWebアプリを表示させるアプリを作った時にやったことをメモした。


背景と目的

最近、Webアプリでユーザージェスチャーなしで音声が自動再生されるようにしようとしたところ、ブラウザの制約上どうしても難しいことが分かった。(Web上で調べると、できるとかできないとかいろいろ情報が錯綜しているのだが、数年前の情報が中心で、2020年6月時点で最新の主要なWebブラウザでは、動画で音量ゼロなら可能そうだが、音声のみのメディアファイル自動再生はできないようだ。やってみたがやっぱりうまくいかなかった。)そこで、この制約をどうにか乗り越えたいので、WebViewを使ってWebアプリを表示させるだけのAndroidアプリを作った。そのときに雑多にハマった内容が多かったのでメモしておく。


詳細

0.前提

0.1 表示対象のWebアプリ主な仕様

  • 常にフルスクリーン
  • http通信
  • ユーザージェスチャーなしで音声を再生(ブラウザ制約で実現できていないので、WebViewを使ったネイティブアプリで実現した)
  • javascriptを使用

0.2 使用端末

  • NEC TE507
    • Android 9(アプリ)
    • WebViewで使用するエンジンはChrome バージョンは83.0.4103.83

0.3 Androidアプリで実現したい最低限の機能

  • スワイプでリロード
  • 0.1の機能がすべて動く


1. フルスクリーン表示

プロジェクト作成時に、fullscreen layoutのアクティビティのサンプルコードを使用すると簡単。いちばん外側のFrameLayoutの直下にあるTextViewをWebViewに置き換えればOK。

<TextView ...

<WebView ...

また、コードの方は、mContentViewというオブジェクトがTextViewなので、これをWebViewに置き換えればOK。

private TextView mContentView;
↓
private WebView mContentView;

あと、onCreateメソッドにある以下の部分を変更。

mVisible = true;
↓
mVisible = false;


2. スワイプで更新

こちらなどを参考に実装。以下のようにSwipeRefreshLayoutでWebViewを囲む。

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipeToRefresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <WebView
        android:id="@+id/fullscreen_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:keepScreenOn="true"
        android:text="@string/dummy_content"
        android:textColor="#33b5e5"
        android:textSize="50sp"
        android:textStyle="bold" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

さらに、onCreateメソッドで、

        mContentView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toggle();
            }
        });
        final SwipeRefreshLayout swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipeToRefresh);
        swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                // Insert your code here
                mContentView.reload(); // refreshes the WebView

                // プログレスインジケータが表示されたままなので3秒後に消す
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // 更新が終了したらインジケータ非表示
                        swipeLayout.setRefreshing(false);
                    }
                }, 3000);
            }
        });


2. ユーザージェスチャーなしで音声を再生

mContentView.getSettings().setMediaPlaybackRequiresUserGesture(false);


3.javascriptを使用

mContentView.getSettings().setJavaScriptEnabled(true);


4. HTTP通信

今回のWebアプリをホスティングしているのはHTTP通信のサーバだったので、HTTP通信が必要なのだが、Androidアプリのポリシー上マニュフェストファイルにusesCleartextTrafficの追加が必要だった。これがないと、ERR_CLEARTEXTどうのこうのというエラーが出る。HTTPSならいらない。

<application
:
android:usesCleartextTraffic="true"
:
>
以下省略


5.jqueryを使用

jqueryCDNから読み込んでいるが、以下ががないと、読み込めない旨のエラーが出る。CDNじゃなくても出るのかな???わからない。

mContentView.getSettings().setDomStorageEnabled(true);


6. MQTTを使用

MQTTについては、特に引っかかるところはなく、何もしなかった。状況としてはjqueryとあまり変わらないので、もしかして、5をやったついでに回避できたのかもしれない???


7. Android Studio上に、Webアプリのjavascriptデバッグコンソールの内容を表示させる

Webアプリの機能ではないが、デバッグ時に使用。

        mContentView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onConsoleMessage(ConsoleMessage cslMsg) {
                Log.d("MyApp", cslMsg.message() + " at line "
                        + cslMsg.lineNumber() + " of "
                        + cslMsg.sourceId());
                return super.onConsoleMessage(cslMsg);
            }
        });


まとめと今後の課題

WebViewを使ううえでこまごました設定などがあって面倒だったがどうにかアプリが動いてよかった。