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が生成されます。

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ファイルを表示します。

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

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

画面右下にクエリパラメータが表示されます。送信したクエリパラメータNUM=1&DEV1=D0&TYP1=Wが正しく送信されていることが確認できます。
Live Serverに保存したホームページから、他のサイト(今回は「Webhook.site」)にアクセスすることをクロスオリジン・リクエストと言います。多くのWebサイトはクロスオリジン・リクエストを禁止しています。ホームページのダウンロード元をオリジンと言います。今回のハンズオンの環境はクロスオリジン・リクエストのため、ブラウザの開発ツールで次のエラーが発生します。
サーバ側の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ページ」を表示します。

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

開発者ツールに「HTTP Status」200が表示されれば成功です。
受信したJSONデータをコンソールに表示します。コメントの「デバッグ用」と書かれている所に、次のプログラムを追加します。
console.log(await response.json());
送信ボタンを押すと、開発者ツールのコンソール画面に受信したJSONデータが表示されます。

図は、RETが0000で「成功」を意味しています。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は別のファイルに分けます。