赤外線リモコン温湿度センサ部品の取付け

##作成のきっかけ
毎朝TVの音声映像で目覚まし時計かわりに起床したいと、ラズパイ赤外線リモコンを作ることにした。
参照した記事は、
1. [ 格安スマートリモコンの作り方 ](https://qiita.com/takjg/items/e6b8af53421be54b62c9)
2. [ Raspberry Pi zero W + IR - something tech.](https://blog.web-apps.tech/raspberry-pi-zero-w-ir/)
この2つの記事を見て出来そうな気がして取り掛かる。
部品の入手は、記事の通りに [秋月電子通商](http://akizukidenshi.com/) で購入した。追加したものは、手元にあった2つ
(1) 高輝度LED(ELEKIT LK-5RD 5個入) 購入当時 200円
(2) 高精度気圧センサーモジュール(BME280) 購入当時 660円x4
も載っけた。

老眼で手元が見にくいし不器用なのでユニバーサル基板ハンダ付けに自信なかったが、ミスっても何度でも作ればとチャレンジすることした。

記事の通りにブレッドボードに部品を挿して動作確認し、ユニバーサル基板へのハンダ付けを始める。
#部品のハンダ
電子部品8点を基板に載っけてはハンダしていく。
補足説明として、
(1)赤保護カバーと接近するので、BME280 VCC 3.3Vのジャンパ橙色1番ピンは先に配線した。BME280ジャンパ黒GNDは25番ピン、緑SCLは3番ピン、黄SDAは2番ピンに接続。
(2)赤外線受光部のoutputは、12ピンのGPIO18に黄色保護カバーでジャンパ(足の長さは足りた)している。近い位置の21ピンのGPIO9でも良かったかも。
(3)赤外線LEDの足の長いほうが1W27ΩR2抵抗側で足の短い方LED受光部に近い側に欠けあり(真上画像で上側)、赤外線LEDと高輝度LEDをつなぐとき高輝度LEDの足の長いほうがLED受光部に近い側で足の短い方9ピンGND側に欠けあり(真上画像で下側)。


| 赤外線LED基盤_真上 | 部品8点追加.GIF |
|:------:|:------:|
|<img width="266" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/a2dbfbb9-e16f-ddb1-7b7a-65f50df60fe3.jpeg">|<img width="266" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/359a10ac-c9ae-28d0-a6ca-7d1570f0b292.gif">|
4方向斜めから見た画像

| 基盤_斜め1 | 基盤_斜め2 | 基盤_斜め3 | 基盤_斜め4 |
|:------:|:------:|:------:|:------:|
|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/27ddd2d2-4817-046a-c5ff-d31fa729e544.jpeg">|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/2ec7e358-963c-a740-5a13-261bd13db0d4.jpeg">|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/7ef5a234-8424-ad89-da1a-e25d3292d361.jpeg">|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/4e755ff3-38cb-5f38-32ac-59aa35df8c95.jpeg">|
3つ作ったがいずれもちゃんと動いたので、たぶん配線は正しかったのだろう。

##設置と動作確認
ケースもどきに入れてテスト設置する。100均ブックエンドに貼り付けたラズパイ赤外線リモコンは2.8m先のTVにミスなく操作できている。とりあえずダンボールの上だがこのまま仮の末代になりそう。赤外線LED発信は指向性ありで反応しないときは、LEDの向きを変えると動いた。赤外線LED受信は発信リモコンが近すぎると正しく読めないようだ。50cmくらい離して赤外線受信学習している。

| ケース上 | ケース底 | 設置 | 設置拡大 |
|:------:|:------:|:------:|:------:|
|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/1d41ebcd-d8ec-552a-da20-334ad4df61a4.jpeg">|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/85663bac-62c9-90a7-7de8-038f1c105ecd.jpeg">|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/bc5bfccb-fc4d-6488-d368-a7a02fd56a82.jpeg">|<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/91295201-4579-c8a7-b56d-660eb0727808.jpeg">|

##追記 2021.9.16 温湿度センサーの分離

BME280温湿度センサー基盤をユニバーサル基板に直付けすると、PiZeroWの熱で温度が4度くらい高くなる。4ピンのジャンパー線で分離したほうが良いだろう。

| 温湿度センサー4ピン_1 | 温湿度センサー4ピン_2 |
|:------:|:------:|
|<img width="266" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/64b98c70-1d80-726e-3c8f-3e9df32b98c2.jpeg">|<img width="266" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/38246dd5-9f11-2143-f668-3e130fd53d0a.jpeg">|

##リモコン操作設定
```shell-session
$ grep Gpi /etc/crontab  # 毎日あさ6:59に起動させる
59 6 * * *	user	/home/user/Gpio/tvpower_nhk.sh
$  　　　　　　　　　　# 毎日メールを送る必要はないけどとりあえず動いている
$ cat /home/user/Gpio/tvpower_nhk.sh
#!/bin/bash
IDNT='$Id: tvpower_nhk.sh,v 1.00 2021/08/18 16:50:50 user Exp $'
PROGNAME=$(basename $0)
cd /home/user/Gpio
ExecMailSend() {
    MDHM=`date '+%Y/%m/%d(%a) %H:%M:%S'`
    SUBJECT=$1
    LISTFILE=$2
    LOGFILE="$LISTFILE"
    SEND_ADDR="username@nifty.com"
    (echo "Mime-Version: 1.0"; echo "Content-Type: Text/Plain; charset=iso-2022-jp"; echo "Content-Transfer-Encoding: 7bit"; echo "Subject: $SUBJECT"; echo "To: ${SEND_ADDR}"; echo "From: tpol5-obs@yahoo.co.jp"; echo "from `hostname`: ${MYCMD} Running LOG."; echo "LISTFILE=$LOGFILE"; nkf -j $LISTFILE) | /usr/sbin/exim4 -f username@yahoo.co.jp ${SEND_ADDR}
}

CTIME=`date '+%Y/%m/%d(%a)%H:%M:%S'`
CMDHM=`date '+%m/%d %H:%M'`
  YY1=`date '+%Y'`
  MM1=`date '+%m'`
  DD1=`date '+%d'`
  HM1=`date '+%H%M'`
PROGNAME=$(basename -s .sh $0)
PROGLOG=/tmp/${PROGNAME}.log
PROGERR=/tmp/${PROGNAME}.err
MYCMD=$0
MYNM=`basename $0`
echo "START=`date`" > $PROGLOG
echo "COMMAND=$MYNM $CMND" >> $PROGLOG
echo "" >> $PROGLOG
echo "$ python3 irrp.py -p -g17 -f codes tvpower" >> $PROGLOG
(python3 irrp.py -p -g17 -f codes tvpower 2>&1) >> $PROGLOG

echo "$ sleep 12" >> $PROGLOG
(sleep 12 2>&1) >> $PROGLOG

echo "$ python3 irrp.py -p -g17 -f codes dg:chan1" >> $PROGLOG
(python3 irrp.py -p -g17 -f codes dg:chan1 2>&1) >> $PROGLOG
echo "" >> $PROGLOG
echo "END=`date`" >> $PROGLOG
ExecMailSend "$PROGNAME ${CMDHM}" "$PROGLOG"
$
```

##BME280のセンサーデータの記録
こちらの記事の通りに
[温度・湿度・気圧・照度をRaspberry Pi 3B+ で24時間監視する](https://iot-plus.net/make/raspi/env-monitoring-rpi3b-plus-bme280-tsl2561/)
を設置してrpz-sensorを少し修正する。

$ diff rpz-sensor/python3/rpz_sensor.py rapi_sensor/python3/rpz_sensor.py

```diff
54,56c54,56
<         loglist[2] = '{:.1f}'.format(bme280ch2.T)
<         loglist[4] = '{:.1f}'.format(bme280ch2.P)
<         loglist[6] = '{:.1f}'.format(bme280ch2.H)
---
>         loglist[1] = '{:.1f}'.format(bme280ch2.T)
>         loglist[3] = '{:.1f}'.format(bme280ch2.P)
>         loglist[5] = '{:.1f}'.format(bme280ch2.H)
76c76
<             datestr = datetime.now().strftime("%Y/%m/%d %H:%M")
---
>             datestr = datetime.now().strftime("%s")+"000"
$ 
```

次に示す cron_bme.sh は10分おきに起動してセンサーデータを得ている。

```shell-session
$ grep bme /etc/crontab   # 10分おきに起動させる
*/10 * * * *    root    /usr/local/BME280/rapi_sensor/python3/cron_bme.sh

$ cat /usr/local/BME280/rapi_sensor/python3/cron_bme.sh
#! /bin/bash
# $Id: cron_bme.sh,v 1.10 2019/02/13 16:50:50 RDH_team Exp $
### This Path is /usr/local/BME280/rapi_sensor/python3/cron_bme.sh
LOG_DIR="/usr/local/BME280/rapi_sensor/Log"
LOG_FILE="${LOG_DIR}/now_bme.txt"
APP1="/usr/local/BME280/rapi_sensor/python3/rpz_sensor.py"

# */10 * * * * ${APP1} -l ${LOG_DIR}/env.$(date +\%Y\%m\%d).csv > /dev/null
# echo  ${APP1} -l ${LOG_DIR}/env.$(date +\%Y\%m\%d).csv > /dev/null
YMD=$(date +\%Y\%m\%d)
${APP1} -l ${LOG_DIR}/env.${YMD}.csv > /dev/null

CTIME=`date '+%Y/%m/%d(%a)%H:%M:%S'`
echo -n "${CTIME} " > $LOG_FILE
${APP1} >> $LOG_FILE

CMDHM=`date '+%m/%d %H:%M'`
  YY1=`date '+%Y'`
  MM1=`date '+%m'`
  DD1=`date '+%d'`
  HM1=`date '+%H%M'`
#bme280log="/var/log/bme280.log"
bme280log="/var/www/html/bme/${YY1}/${MM1}/bme280_${DD1}.log"
export MMDIR="/var/www/html/bme/${YY1}/${MM1}"
if [ ! -d ${MMDIR} ]; then
    mkdir -p ${MMDIR}
    if [ $? != 0 ]; then
        echo "$CTIME Cannot mkdir $MMDIR." >> /var/log/bme280.log
    fi
fi

cp ${LOG_DIR}/env.${YMD}.csv /var/www/html/bme/latest.csv
cp ${LOG_DIR}/env.${YMD}.csv ${MMDIR}/${DD1}.csv

cp ${LOG_DIR}/env.${YMD}.csv /var/www/html/log/latest.csv
cp ${LOG_DIR}/env.${YMD}.csv /var/www/html/log/${YMD}.csv
$
```
##BME280のセンサーデータの表示
```shell-session
    # 記事にあるindex.htmlを[変更読込み]のところを追加している。
$ cat /var/www/html/indexB.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>indexB.html</title>
<script type="text/javascript">

    var yy, mm, dd, today;
    today = new Date();
    yy = today.getFullYear(); // 年
    mm = today.getMonth() + 1; // 月
    dd = today.getDate(); // 日
    var hour = today.getHours(); // 時
    if ( hour < 10 ) {
        hour = "0" + hour;
    }
    var minute = today.getMinutes(); // 分
    if ( minute < 10 ) {
        minute = "0" + minute;
    }
    var dayOfWeek = today.getDay(); // 曜日(数値)
    var dayOfWeekStr = [ "日", "月", "火", "水", "木", "金", "土" ][dayOfWeek];  // 曜日(日本語表記)
      window.addEventListener('load', function NewDate() {
	  //年
	  $Year = '<select id="selyear">';
	  for( var i=2018; i<=2025; i++ ){
              if( i == yy){
		  $Year += "<option value=\"" + i + "\" selected >" + i + "</option>";
              }else{
		  $Year += "<option value=\"" + i + "\" >" + i + "</option>";
              }
	  }
	  $Year += "</select>";
	  document.getElementById("year").innerHTML = $Year + "年";
	  //月
	  $Month = '<select id="selmonth">';
	  for( var i=1; i<=12; i++ ){
              if( i == mm){
		  $Month+= "<option value=\"" + i + "\" selected >" + i + "</option>";
              }else{
		  $Month+= "<option value=\"" + i + "\" >" + i + "</option>";
              }
	  }
	  $Month += "</select>";
	  document.getElementById("month").innerHTML = $Month + "月";
	  //日付
	  $Day = '<select id="selday">';
	  for( var i=1; i<=31; i++ ){
              if( i == dd){
		  $Day+= "<option value=\"" + i + "\" selected >" + i + "</option>";
              }else{
		  $Day+= "<option value=\"" + i + "\" >" + i + "</option>";
              }
	  }
	  $Day += "</select>";
	  document.getElementById("day").innerHTML = $Day + "日";
      })

      var now = new Date();
      var ymdURL1 = new String();
      var ymdURL3 = new String();
      var ymdURL5 = new String();
      var baseURL = location.origin;
      window.addEventListener('load', function LoadProc() {
	  var target = document.getElementById("DateTimeDisp");
	  var Year = now.getFullYear();
	  var Month = now.getMonth()+1;
	  var Date = now.getDate();
	  target.innerHTML = Year + "年" + Month + "月" + Date + "日(" + dayOfWeekStr + ") " + hour + ":" + minute;
      })
      window.addEventListener('load', function LoadProc() {
	  var target = document.getElementById("DateTimeDisp2");
	  var Year = now.getFullYear();
	  var Month = now.getMonth()+2;
	  var Date = now.getDate();
	  target.innerHTML = Year + "年" + Month + "月" + Date + "日";
      })
      window.addEventListener('load', function LoadProc() {
	  var target = document.getElementById("DateTimeDisp3");
          if ( mm < 10 ) {
              mm = "0" + mm;
	  }
          if ( dd < 10 ) {
              dd = "0" + dd;
	  }
	  var result = "/" + yy + "/" + mm + "/" + dd;
	  var ymdURL = baseURL + '/bme' + result + ".csv";
	  target.innerHTML = ymdURL;
      })
      window.addEventListener('load', function LoadProc() {
	  var target = document.getElementById("DateTimeDisp4");
	  var result = yy + "&mm=" + mm + "&dd=" + dd;
	//ymdURL = "http://rapiv.local/indexB1.html?yy=" + result;
	  ymdURL1 = baseURL + '/indexB1.html?yy=' + result;
	  ymdURL3 = baseURL + '/indexB3.html?yy=' + result;
	  ymdURL5 = baseURL + '/indexB5.html?yy=' + result;
	  target.innerHTML = ymdURL1;
	  // "http://rapiv.local/indexB1.html?yy=2019&mm=01&dd=18"
	  document.getElementById("ifr1").src = ymdURL1;
	  document.getElementById("ifr3").src = ymdURL3;
	  document.getElementById("ifr5").src = ymdURL5;
      })
      window.addEventListener('click', function onButtonClick() {
	  var target = document.getElementById("DateTimeDisp5");
          yy = document.getElementById('selyear').value;
          mm = document.getElementById('selmonth').value;
          if ( mm < 10 ) {
              mm = "0" + mm;
	  }
          dd = document.getElementById('selday').value;
	  if ( dd < 10 ) {
              dd = "0" + dd;
	  }
	  var result = yy + "&mm=" + mm + "&dd=" + dd;
	//ymdURL = "http://rapiv.local/indexB1.html?yy=" + result;
	  ymdURL1 = baseURL + '/indexB1.html?yy=' + result;
	  ymdURL3 = baseURL + '/indexB3.html?yy=' + result;
	  ymdURL5 = baseURL + '/indexB5.html?yy=' + result;
	  target.innerHTML = ymdURL1;
	  // "http://rapiv.local/indexB1.html?yy=2019&mm=01&dd=18"
	  document.getElementById("ifr1").src = ymdURL1;
	  document.getElementById("ifr3").src = ymdURL3;
	  document.getElementById("ifr5").src = ymdURL5;
      })

</script>

</head>
<body>
　　今の日時：<span id="DateTimeDisp"></span><br/>
<div style="display:inline-flex">
<b>　変更日付</b>
<a id="year"></a><a id="month"></a><a id="day"></a>
<form>
　　<input type="button" value="変更読込み" onclick="onButtonClick();" />
</form>
</div><br/>
　　本日URL：<a id="DateTimeDisp4"></a><br/>
　　変更URL：<a id="DateTimeDisp5"></a><br/>
<!--div style="font-size:32px;">Temperature</div src="http://rapiv.local/indexB1.html?yy=2019&mm=01&dd=11" -->
<!-- id="ifr" https://teratail.com/questions/41623  -->
<iframe src="" id="ifr1" width="100%" height="330px">iframeに対応していません。</iframe>
<br />

<iframe src="" id="ifr5" width="100%" height="330px">iframeに対応していません。</iframe>
<br />

<iframe src="" id="ifr3" width="100%" height="330px">iframeに対応していません。</iframe>
<br />
</body>
</html>
$

$ cat /var/www/html/indexB1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>indexB1 Chart using XML Data</title>
<script type="text/javascript" src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<script type="text/javascript">
  // http://rapiv.local/indexB1.html?yy=2019&mm=01&dd=24
  window.onload = function() {
      /* https://www.ipentec.com/document/javascript-get-parameter */
      param = GetQueryString();
      target = document.getElementById("urlparam");
      var ymdURL = new String();
      var baseURL = location.origin;
      ymdURL = baseURL + '/bme' + param + '.csv';
      target.innerHTML = ymdURL;
      function GetQueryString() {
            if (1 < document.location.search.length) {
                // 最初の1文字 (?記号) を除いた文字列を取得する
                var query = document.location.search.substring(1);
                // クエリの区切り記号 (&) で文字列を配列に分割する
                var parameters = query.split('&');
                var result = new String();
                for (var i = 0; i < parameters.length; i++) {
                    // パラメータ名とパラメータ値に分割する
                    var element = parameters[i].split('=');
                    //var paramName = decodeURIComponent(element[0]);
                    var paramValue = decodeURIComponent(element[1]);
                    // パラメータ名をキーとして連想配列に追加する
                    //result[paramName] = decodeURIComponent(paramValue);
		    result = result + '/' + paramValue;
                }
                return result;
            }
            return null;
      }

        var dataPoints = [];
        function getDataPointsFromCSV(csv) {
            var dataPoints = csvLines = points = [];
            csvLines = csv.split(/[\r?\n|\r|\n]+/);

            for (var i = 0; i < csvLines.length; i++)
                if (csvLines[i].length > 0) {
                    points = csvLines[i].split(",");
                    dataPoints.push({
                        x: parseFloat(points[0]),
                        y: parseFloat(points[1])
                    });
                }
            return dataPoints;
        }

        //$.get("http://rapiv.local/log/latest.csv", function(data) {
        $.get(ymdURL, function(data) {
            var chart = new CanvasJS.Chart("chartContainer", {
                    title: {
                         text: "",
                    },
                    axisX:{
                        title: "time",
                    },
                    axisY:{
                            title: "Temperature (C)",
                               minimum: 0,
                               maximum: 60,
                    },
                    data: [{
                         type: "area",
                         xValueType: "dateTime",
                         dataPoints: getDataPointsFromCSV(data)
                      }]

             });

              chart.render();

        });
  }
</script>
</head>
<body>
   表示ＵＲＬ：<span id="urlparam"></span><br/>
<div id="chartContainer" style="width:100%; height:300px;"></div>
</body>
</html>
$

$ diff /var/www/html/indexB1.html /var/www/html/indexB3.html
51c51
<                         y: parseFloat(points[1])
---
>                         y: parseFloat(points[3])
67,69c67,69
<                             title: "Temperature (C)",
<                                minimum: 0,
<                                maximum: 60,
---
>                             title: "Atmospheric pressure (hPa)",
>                                minimum: 930,
>                                maximum: 1130,

$ diff /var/www/html/indexB1.html /var/www/html/indexB5.html
51c51
<                         y: parseFloat(points[1])
---
>                         y: parseFloat(points[5])
67c67
<                             title: "Temperature (C)",
---
>                             title: "Humidity (%RH)",
69c69
<                                maximum: 60,
---
>                                maximum: 100,
$
```

HTMLやjavascriptは知識に乏しく、きれいなコードが書けないでいる。
パス/var/www/html/indexB1.html
この、`"http://rapii.local/indexB.html"` は、[変更読込み]ボタンで過去の日付の温湿度気圧のグラフが表示できるようにしている。

| 温湿度気圧グラフ例 |
|:------:|
|<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499844/797840d2-6e3b-8e97-234b-5966dc4f0c08.jpeg">|

crontabで10分おきに温湿度気圧を得ている。直近のデータは以下のテキストに記録した。

```shell-session
$ cat /usr/local/BME280/rapi_sensor/Log/now_bme.txt
2021/08/31(Tue)17:30:01 BME280 0x76
 Temp     : 28.0C
 Pressure : 1012.0hPa
 Humidity : 61.0%
$
```