マナビDX Quest：QRコードでのデジタル化 -DXへの第一歩-

この記事は[マナビDX Questで得たもの Advent Calendar 2023](https://qiita.com/advent-calendar/2023/manabi-dx-quest2023)　6日目の記事です。
（昨日は@edamoto さんの記事でした👏）
今回がQiitaで初投稿となります。よろしくお願いします。

## 自己紹介
製造業の設計開発部門でハードウェアの電気や制御に関する業務をしています。
昨年度のマナビDX Quest2022を修了し、今年度のマナビDX Quest2023も受講しています。

## 記事の概要
昨年度のマナビDX Quest2022を修了して今年度のマナビDX Quest2023を受講するまでの前日譚となります。

QRコードを使ったデモアプリを作って、「社用携帯をガラホ（ガラケー型スマートフォン）から通常のスマホに変えるとこんな有効活用ができますよ」と社内で紹介した話の中で、**Qiitaなのでエンジニアっぽい部分を抜粋**して記事にしています。

### DXQRとは
**DX**と**QRコード**というワードから作り出した「**DXQR**」の３つの意味を紹介します。実際に使われている機会は見かけないのでご参考程度としてください。（報告資料側ではこのワードを使用）
1. 「Digital Transformation Quick Response」の略
　デジタルトランスフォーメーションにおいて、迅速な対応が求められることを表す言葉です。企業が急速に変化する市場環境に対応するために、迅速な意思決定やアクションが必要とされます。DXQRは、そのような状況において、素早く対応することができる能力を指します。
1. 「Data Exchange Quick Response」の略
　データ交換において、迅速な応答が求められることを表す言葉です。DXQRは、データの送受信において、高速かつ正確な応答を返すことができる技術やシステムを指します。例えば、QRコードを利用したデータのやり取りにおいて、DXQRを実現することができます。
1. 「MANABI-DELUXE-QUEST for Reskilling」（※）の略で、必要なスキルを獲得するためのマナビDX Questという造語です。ここでのDELUXEは「Digitaltransformational Education and Learning platform for Users × Engineers」の略のようです。

３つの意味を引用して、**マナビDX Questで得たもの**から、**QRコードを利用したデータのやり取り**を利用して、**迅速な意思決定やアクション**を促そうという意味合いを表現しています。

### QRコードとは
QRコードは株式会社デンソーウェーブが開発した2次元コードです。
QRコードを使用するにあたり、申請不要で誰でも自由に使うことができますが、「QRコード」の名称を使用する場合は、原則として「**QRコードは株式会社デンソーウェーブの登録商標です**」といった登録商標文の記載が必要です。該当媒体のいずれかのスペースに記載するようにしましょう。

QRコードについて詳しく知りたい方は下記の記事をご参考に。
https://b.qrqrq.com/2023/03/10/about_qr_code/

### 想定している読者
+ QRコードやWEBアプリに興味のある方
+ 来年度以降のマナビDX Questを受講したいと考えている方

## マナビDX Questとは
Advent Calendarのテーマなので簡単にご説明します。
<参照記事>
①[デジタル推進人材育成プログラム「マナビDX Quest」](https://dxq.manabi-dx.ipa.go.jp/)
②[「マナビDX Quest」について（METI/経済産業省）](https://www.meti.go.jp/policy/it_policy/jinzai/manabi-dx-quest.html)

+ 地域企業・産業のDXの実現に向け、ビジネスの現場における課題解決の実践を通じてデジタル知識・能力を磨くため、経済産業省が実施する学生・社会人を対象にしたデジタル推進人材育成プログラムです。
+ マナビDX Questは、企業データに基づく実践的なケーススタディ教育プログラム及び、地域の中小企業との協働による、デジタル技術を活用した地域企業協働プログラムからなります。
+ マナビDX Questを通じて、デジタルの経験有無にかかわらず企業におけるDXを推進する変革の考え方やプロセスを学び、志を同じくする幅広いデジタル人材とのつながりを構築することができます。

### マナビDX Questでの醍醐味
:::note info
<font color="DeepPink">**「競争」と「共創」**</font>
:::
マナビDX Questでは講師による座学ではなく、参加者が情報交換して学び合い・教え合いながら、与えられた課題を解決していくことでのマナビが大きいです。
参加者は、パフォーマンスを競い合うライバルであり、同時に学び合う仲間でもあります。切磋琢磨しながら課題を解決していく中で、志を同じくする参加者との繋がりができます。
また、受講後も過年度参加者が集う「修了生コミュニティ」に参加し、継続的な学びや交流の機会を得られます。

# QRコードデモアプリの概要
前置きはここまでにして、本題の**QRコードデモアプリ**について説明していきます。
デモアプリは製造現場の工数管理をQRコードを利用してもできることを周知する目的として作成しています。
WebサーバソフトのApacheをノートPCに入れて同一ネットワーク上のスマホ、タブレットを接続する形式でのデモ運用を想定しています。
デモアプリなので、開発工数削減のため**CSVファイルで情報を管理し、DBでの管理や運用でのセキュリティリスクを考慮していません。**

:::note warn
QRコードはMicrosoft Power AppsやGoogle AppSheetなどのローコードツールでも利活用できますが、今回はHTML、PHP、JavaScriptでのコーディングをしています。
:::

# 環境構築
デモ環境構築にはXAMPP（ザンプ）をインストールし、Webサーバソフトの「Apache」、スクリプト言語の「PHP」を利用してWebアプリケーションの作成をしました。
デモの際には同一ネットワーク上のスマホ、タブレットを接続する形式としました。

参考までに構成品も記載しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621208/00cea9bc-cae0-5ece-a2de-e6bdaa717445.png)



### 構成品
+ ノートPC（Windows 11）
+ iphone 11
+ iPad Air（第3世代）

## 実装機能
デモアプリに実装の機能は下記となっています。デモのため最低限の機能となっています。

### スマホ用
1. **ユーザ登録**
スマホでユーザ登録し、サーバ内の「ユーザ.csv」に登録情報を記録する
1. **ユーザログイン**
スマホでログイン情報を入力しし、サーバ内の「ユーザ.csv」を参照しログインする
1. **作業項目選択**
ユーザが現在作業可能な作業をリスト表示する
1. **作業用QRコード表示**
各種情報が記載されたQRコードを表示する
1. **履歴の参照**
サーバ内の「(社員番号).csv」を参照して履歴を表示する

### タブレット画面用
1. **QRコードをタブレットのカメラで読み取る**
タブレットのカメラをブラウザで動作させ、QRコードの識別をする
1. **QRコード判定**
識別されたQRコードのデータ内容を判定する
1. **QRコードデータのサーバ登録**
データの情報をサーバ内の「(社員番号).csv」と「dijest.csv」に記録する

### 管理端末用
1. **ユーザログイン**
管理用画面にログインする
1. **履歴の参照**
ユーザの作業状況を表示する
1. **ユーザの登録、削除**
管理者権限でユーザの登録と削除をする

# 実装
### タブレット用
QRコードの読み込みには「[jsQR](https://github.com/cozmo/jsQR)」というjQuery、音声を出すために「[howler.js](https://github.com/goldfire/howler.js#documentation)」というJS、カメラを動作させるには「[MediaDevices: getUserMedia()](https://developer.mozilla.org/ja/docs/Web/API/MediaDevices/getUserMedia)」メソッドを利用しています。

音声を出すために「[ウェブオーディオ API](https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API)」という方法もありますが、ブラウザごとの対応が非常に面倒であったので、「howler.js」を利用しています。

カメラを動作させるための「MediaDevices: getUserMedia()」メソッドはブラウザのセキュリティ観点でHTTPSでのみ利用できるので注意が必要でした。また、ブラウザのセキュリティポリシーは日々変更されているので、いつ使えなくなるかわからないので注意が必要です。

ソースコードは記載が長くなりそうなので部分抜粋して記載します。


<details><summary>サンプルコード</summary>
ヘッダ部

```php
<?php
	require_once 'common.php';
?>

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>
            QRリーダ
        </title>
        <link rel="stylesheet" href="../css/style.css">
        <script src="../js/jsQR.js"></script>
        <script src="../js/howler.min.js"></script>
    </head>
```

ボディ部（カメラ動作部）
※省略箇所があるため、そのままでは正常に動作しません。
```html
<script>
    let video = document.createElement("video");
	let canvasElement = document.getElementById("canvas");
	let canvas = canvasElement.getContext("2d");
	let loadingMessage = document.getElementById("loadingMessage");
	let outputContainer = document.getElementById("output");
	let outputMessage = document.getElementById("outputMessage");
	let outputData = document.getElementById("outputData");
	let HeadText = document.getElementById("head");
	let ResultImageOK = document.getElementById("resultImageOK");
	let ResultImageNG = document.getElementById("resultImageNG");
	let PageNum = 1;
	let text ="";
	const oksound = new Howl({
		src: ['../mp3/ok.mp3'],
		//html5: true
	});
	const ngsound = new Howl({
		src: ['../mp3/ng.mp3'],
		//html5: true
   	});

	function ShowPage1(){
		PageNum = 1;
		HeadText.innerHTML = "ＱＲコードを提示してください";
		if (video.readyState === video.HAVE_ENOUGH_DATA) {
			loadingMessage.hidden = true;
			canvasElement.hidden = false;
			outputContainer.hidden = false;
			outputMessage.hidden = false;	
		}else{
			loadingMessage.hidden = false;
			canvasElement.hidden = false;
			outputContainer.hidden = false;
			outputMessage.hidden = false;
		}
		ResultImageOK.hidden =true;
		ResultImageNG.hidden =true;
	}


	function enquiry(text) {
		//判定照会
		//細かい処理のため省略
	}
		
	function drawLine(begin, end) {
		canvas.lineWidth = 4;
		canvas.strokeStyle = "#FF3B58";
		canvas.beginPath();
		canvas.moveTo(begin.x, begin.y);
		canvas.lineTo(end.x, end.y);
		canvas.stroke();
	}
		
	function drawRect(location){
		drawLine(location.topLeftCorner, location.topRightCorner);
		drawLine(location.topRightCorner,location.bottomRightCorner);
		drawLine(location.bottomRightCorner, location.bottomLeftCorner);
        drawLine(location.bottomLeftCorner,location.topLeftCorner);
	}
		
	// facingMode: environment：リアカメラ　user:フロントカメラ
		
	const userMedia = {audio: false, video: {facingMode: "environment"}};

	navigator.mediaDevices.getUserMedia(userMedia).then(function(stream) {
		//videoにWebカメラで流れてくる情報(stream)を与えることを設定
		video.srcObject = stream;
		//再生領域内で再生
		video.setAttribute("playsinline", true);
		//ビデオ再生を開始
		video.play();
		//画面更新時にtick関数を呼ぶように設定
		requestAnimationFrame(tick);
		}).catch(function(err) {
		// エラー
	});
		
	function tick() {
		if(PageNum == 1){
			if (video.readyState == video.HAVE_ENOUGH_DATA) {
				loadingMessage.hidden = true;
				canvasElement.hidden = false;
				outputContainer.hidden = false;
					
				//canvasのサイズをビデオサイズに統一
				canvasElement.height = video.videoHeight;
				canvasElement.width = video.videoWidth;
					
				//canvasにvideoのあるフレームを貼り付け
				canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
					
				//videoから取り出したデータをimageDataに変換
				var image = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
					
				//jsQRでQRコード読み取り処理を実施
				var code = jsQR(image.data, image.width, image.height, { inversionAttempts: "dontInvert", });
					
				//読み取ったQRコードで結果表示を切り替え
				if (code) {
					text = code.data;
					if(text !=""){
						drawRect(code.location);// Rect
						outputMessage.hidden = true;
						outputData.parentElement.hidden = false;
						outputData.innerText = code.data;
						enquiry(text);
					}else{
					}
				} else {
					outputMessage.hidden = false;
					outputData.parentElement.hidden = true;
				}
			}
		}
		requestAnimationFrame(tick);
	}
</script>
```

</details>

### スマホ画面用
QRコードの出力には「qrcode.min.js」を利用しています。
こちらも記載が長くなりそうなので部分抜粋して記載します。

<details><summary>サンプルコード</summary>

ヘッダ部
```php
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=yes, maximum-scale=1.0, minimum-scale=1.0">
  	<title>ＱＲコード表示画面</title>
	<meta name="keywords" content="">
	<meta name="description" content="">
	<link rel="stylesheet" href="../css/style.css" type="text/css" media="screen">
    <script src="../js/qrcode.min.js"></script>
</head>
```
ボディ部（QRコード表示）
```php
<div id="qrcode" style="width:128px;margin:0 102px; auto;">
    <script>
        new QRCode(document.getElementById("qrcode"), {
            text: "<?= h($qrtext) ?>",
            width: 128,
            height: 128,
            colorDark : "#000000",
            colorLight : "#ffffff",
            correctLevel : QRCode.CorrectLevel.H
        });
    </script>
</div>
```

</details>

### コードに関して
実際に利用したソースコードから公開できない内容や参考にしないほうがよい小細工的な記述を削除しての一部抜粋のため、内容が断片的でわかりづらいと思います。
今のご時世なら**ChatGPTを活用**したソースコードの生成やレビュー、修正もできるので、ぜひ活用してみてください。

### 提案の結果について
:::note warn
社内で紹介した結果
カメラNGの取引先があるから導入は無理！！（知ってました）
:::

# さいごに
いかがでしょうか？

この記事ではあまり触れていませんが、DX推進では「**迅速な意思決定やアクション**」というマインドスタンスも大切になってくるかと思います。

マナビDX Questでは、「**DX推進のための一連のアプローチ方法を学ぶことができる点**」や「**他の参加者との交流を通じて新しい視点や経験を得ることができる点**」がおすすめポイントです。

[マナビDX Questで得たもの Advent Calendar 2023](https://qiita.com/advent-calendar/2023/manabi-dx-quest2023)　ではマナビDX Questで**得たもの**や**面白さ**、**気づき**などを**優秀なみなさん**、**向上心が高いみなさん**が紹介してくれます。来年参加したい人、興味のある方は一連の記事を見ることをおすすめします。

明日は、@CornerBook さんの記事です。
よろしくお願いします！