メインコンテンツまでスキップ

JavaScriptでPLCにアクセス

JavaScriptでPLCにアクセスします。三菱電機製PLCのFX5Uは、次の仕様でアクセスできます。

  • 要求(リクエスト)はクエリパラメータで送信
  • 応答(レスポンス)はJSONデータ形式で受信

クエリパラメータ

クエリパラメータの概要

検索サイトや、ユーザーデータを入力するサイトにアクセスすると、URLの後の「?」マーク以降にクエリパラメータが追加されることがあります。各パラメータは「&」で区切られます。

次の例は、Googleサイトで「PLC」を検索したときのURLです。

https://www.google.com/search?q=PLC&sca_esv=f73d9469f7b455ed&source=hp&ei=RFRMabv5BKTd2roP7cnFaQ&iflsig=AOw8s4IAAAAAaUxiVGgxhsW-ItDbEPikDM9yPQ9qHXs1&ved=0ahUKEwi7q6-Gj9eRAxWkrlYBHe1kMQ0Q4dUDCBY&uact=5&oq=PLC&gs_lp=Egdnd3Mtd2l6IgNQTEMyCxAAGIAEGLEDGIMBMggQABiABBixAzIFEAAYgAQyBRAAGIAEMgUQABiABDIFEAAYgAQyBRAAGIAEMgcQABiABBgEMgUQABiABDIFEAAYgARI_AtQqwdY0QpwAXgAkAEAmAFNoAHaAaoBATO4AQPIAQD4AQGYAgSgAvwBqAIKwgIKEAAYAxjqAhiPAcICDRAAGIAEGLEDGIMBGATCAhAQABiABBixAxiDARgEGIoFwgIKEAAYgAQYsQMYBMICDhAAGIAEGLEDGIMBGIoFmAMK8QXzUvhzNak5apIHATSgB80IsgcBM7gH8gHCBwcwLjEuMi4xyAcZgAgA&sclient=gws-wiz&sei=SFRMafisK4Db2roP6_bg4Qg

アドレスhttps://www.google.com/searchの後に「q=PLC」や「sca_esv=f7…」など、複数のパラメータが「&」記号を挟んで続いています。

PLCで使用するクエリパラメータ

三菱電機製PLCのFX5は、デバイス読み出しや書き込みをクエリパラメータで指定できます。HTTPのPOSTを使用します。HTTPのGETはURLの後ろにクエリパラメータを連結しますが、POSTはHTTPの本体に記述します。そのため、クエリパラメータはURLで確認できません。

PLCのIPアドレスは192.168.3.100とします。読み出しのときの接続先のパスは/cgi/RdDevRnd.cgiです。

クエリパラメータは「名前=値」で設定します。デバイスD0から1点のワードデータを取得するために、クエリパラメータNUM=1&DEV1=D0&TYP1=Wを送信します。

URLSearchParamsによるクエリパラメータの作成

JavaScriptを使ってPOSTでクエリパラメータを送信する方法は複数あります。今回はURLSearchParamsオブジェクトを使用します。

const query = 'NUM=1&DEV1=D0&TYP1=W'
const form = new URLSearchParams(query);

パラメータを個別に設定できます。

const form = new URLSearchParams();
form.set("NUM", 3);
form.set("DEV1", "D0");
form.set("TYP1", "W");

クエリパラメータの送信

FX5Uに要求を送るときは、HTTPのPOSTを使用します。POSTを使うときは、クエリパラメータをURLに設定するのではなく、HTTPのBodyに設定します。 先のサンプルで作成したformオブジェクトを使用します。

Fetch APIで送信

JavaScriptでネットワーク要求を送る方法は複数ありますが、今回はモダンなFetch APIを使用します。

警告

FX5Uにアクセスするときは、ログインで取得したセッションキーを一緒に送信しないとエラーになります。

Fetch APIのサンプル
//const url = "http://172.22.30.100/cgi/RdDevRnd.cgi?NUM=1&DEV1=D0&TYP1=W";
const url = "http://172.22.30.100/cgi/RdDevRnd.cgi";
const response = await fetch(url, {
method: 'POST',
credentials: 'include', // Cookieを送信
cache 'no-store', // キャッシュを使用しない
body: form
});

// デバッグ用
console.log(response.status);
console.log(response.ok);

if (response.ok) {
const text = await response.text(); // テキストで取得
const json = await response.json(); // JSONで取得
console.log(text);
console.log(json);
}

ネットワークの送信を確認するために、サーバーサイドのプログラムを準備する必要があります。今回は、サーバーサイドのプログラムを作らずに確認します。正しいクエリパラメータが送信されることを確認するために「Webhook.site」を使用します。Webhook.siteは、リクエストの情報を表示する無料のサービスです。

「Webhook.site」にアクセスすると、アクセス先のURLが生成されます。

Webhook.siteにアクセスしたときの最初の画面

VS Codeを使用して、次のファイルを作成します。

fetchTest.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Fetch APIのテスト</h1>
Webhook.siteに次のクエリパラメータを送信します。
<pre>
?NUM=1&DEV1=D0&TYP1=W
</pre>
送信ボタンを押すと送信します。結果はブラウザの開発者ツールのコンソールで確認します。
<p>
<button id="send">送信</button>
</p>
<a href="index.html">Top</a>
<script>
const send = document.querySelector("#send"); // IDがsendの要素を取得
send.addEventListener("click", sendQueryParams); // クリックイベントの登録

/**
* クエリパラメータをPOSTで送信
*/
async function sendQueryParams() {
// クエリパラメータの作成
try {
const query = 'NUM=1&DEV1=D0&TYP1=W'
const form = new URLSearchParams(query);

// const form = new URLSearchParams();
// form.set("NUM", 3);
// form.set("DEV1", "D0");
// form.set("TYP1", "W");

// Fetch APIで送信
// URLはWebhook.siteで自動生成されたアドレスを使用してください。
const url = "https://webhook.site/f055d994-20ed-44db-b84f-35be553bb5e7";
const response = await fetch(url, {
method: 'POST',
mode: 'cors', // 別のオリジンサーバへのアクセスを許容
credentials: 'include', // Cookieを送信
cache: 'no-store', // キャッシュを使用しない
body: form
});

// デバッグ用
console.log(response.status);
console.log(response.ok);
} catch (e) {
console.error('fetch error:', e);
}
}
</script>
</body>
</html>

Live Serverなどの機能でローカルで作成したHTMLファイルを表示します。

Fetch APIのテスト

「送信」ボタンを押すと、Webhook.siteにリクエストが送信されて、Webhook.siteのホームページにリクエストの詳細が表示されます。

画面左側に概要が表示されます。

Webhook.siteでリクエストを受信したとき1

画面右上にリクエストヘッダーの内容が表示されます。

Webhook.siteでリクエストを受信したとき1

画面右下にクエリパラメータが表示されます。送信したクエリパラメータNUM=1&DEV1=D0&TYP1=Wが正しく送信されていることが確認できます。

Webhook.siteでリクエストを受信したとき1

注記

Live Serverに保存したホームページから、他のサイト(今回は「Webhook.site」)にアクセスすることをクロスオリジン・リクエストと言います。多くのWebサイトはクロスオリジン・リクエストを禁止しています。ホームページのダウンロード元をオリジンと言います。今回のハンズオンの環境はクロスオリジン・リクエストのため、ブラウザの開発ツールで次のエラーが発生します。 CORSエラー サーバ側のCORS (Cross Origin Resource Sharing) 設定を変更できれば、エラーの発生を防ぐことができます。Webhook.siteは、ユーザ登録するとCORSの設定変更が可能です。


PLCにリクエストを送信

PLCのWebサーバにアクセスするときは認証が必要です。ログインしたときに生成されるセッションキーを要求時に送信する必要があります。ブラウザは同一オリジンのときに自動でセッションキーを送信します。

注記

ログイン後何も操作しないと5分間でログオフされます。ログオフ後に「送信」を押すとエラーになります。5分以上過ぎているときは、ブラウザの画面更新を行い、再度、ログインします。

PLCのユーザーWebページのトップ画面を作成します。index.htmlを作成します。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>PLCのユーザWebページにようこそ!</h2>
<ul>
<li><a href="fetchTest.html">Fetch APIのテスト</a></li>
</ul>
</body>
</html>

fetchTest.htmlのJavaScriptのurl変数を、Webhook.siteからPLCに変更します。

const url = "http://192.168.3.100/cgi/RdDevRnd.cgi";

PLCのFX5にリクエストを送信します。fetchTest.htmlをFX5のSDカードに書き込みます。書き込む手順は「PLC内蔵Webサーバの使い方」を確認してください。

FX5のWebサーバーにアクセスします。アドレスはhttp://192.168.3.100です。ログインした後に「ユーザWebページ」を表示します。

ユーザWebぺージ

「Fetch APIのテスト」をクリックします。

Fetch APIテスト

開発者ツールに「HTTP Status」200が表示されれば成功です。

HTTP Status 200

受信したJSONデータをコンソールに表示します。コメントの「デバッグ用」と書かれている所に、次のプログラムを追加します。

console.log(await response.json());

送信ボタンを押すと、開発者ツールのコンソール画面に受信したJSONデータが表示されます。

受信したJSON

図は、RET0000で「成功」を意味しています。DATAの0番目が001Eで、D0が10進数で30であることが分かります。D0の値は使用しているPLCの状況で変化します。

開発者ツールのネットワーク

ブラウザの開発者ツールの「ネットワーク」で通信の状況を確認できます。「ネットワーク」を開いた後で、ページを更新すると情報が表示されます。「ヘッダー」や「ペイロード」などを調べてください。


練習問題

D0~D3とD100のデータを受信できるように変更してください。

回答例1

回答例 (fetchTest2.html) は、リンクを右クリックしてファイルをダウンロードして確認してください。

解説:

  • PLCのIPアドレスとアクセスするファイル名を変数に保存して、修正しやすくしています。
  • 読み出したいデバイスの種類やタイプを柔軟に変更するために、読み出したいデバイスの情報をJavaScriptオブジェクトのrequestDeviceに保存しています。読み出したいデバイスや追加したいデバイスがあれば、このオブジェクトを変更します。
  • JavaScriptオブジェクトからクエリパラメータを生成するためのcreateQueryParams関数を作成しています。読み出したい情報を設定したURLSearchParamesオブジェクトを返します。
  • PLCのIPアドレス、アクセス先ファイル名と送信するクエリパラメータが引数のsendQueryPrams関数を作成しています。Fetch APIを使用して要求を送信します。ボタンの連続押しの防止機能や、HTTPのエラー応答のときのエラー処理を追加しています。成功するとJSONオブジェクトを返します。
回答例2

HTMLを操作するプログラムはHTMLファイルに残して、関数にしたJavaScriptは別のファイルdeviceRead.jsに分けます。 回答例 (fetchTest3.html) と(deviceRead.js) は、リンクを右クリックして、ファイルをダウンロードして確認してください。

注記

一般的に、HTML、CSSとJavaScriptは別のファイルに分けます。