今更ですが温度センサDS18B20について調べています。

最終修正日:2023/8/16

今更なのですが、温度センサ18B20について調べています。

一般的なセンサですがちゃんと理解して使っている方は少ないように思います。
手元ではSTM32F1に2基接続して、温度観測をしていますが、是非RP2040ボードに移植したいという意向もあって改めて勉強することにしました。

DS18B20

もともとマキシム社が提供して、今ではアナログデバイス社が管理しているようです。評価キットもアナログデバイス社が提供しています。

  • 通信に1つのポートピンのみを必要とする独自の1-WireRインタフェース
  • 温度センサーおよびEEPROMの内蔵によって部品数を削減
    温度測定範囲:-55℃〜+125℃(-67°F〜+257°F)
    精度:±0.5℃(-10℃〜+85℃)
    設定可能な分解能:9ビット〜12ビット
    外付け部品が不要
  • 寄生電源モードは動作に必要な端子が2つ(DQとGND)のみ
  • マルチドロップ機能によって分散温度検出アプリケーションを簡素化
    各デバイスは固有の64ビットシリアルコードを内蔵ROMに保存
  • アラーム検索コマンドを備えた柔軟なユーザー定義不揮発性(NV)アラーム設定によって、設定された温度制限範囲外のデバイスを識別
  • 8ピンSO (150 mil)、8ピンμSOP、および3ピンTO-92パッケージで提供

ブロック図が提供されています。

使用する際には外付けで4.7kΩのPullUp抵抗が必要みたいです。
Vccについての情報が記載されていません。SpecSheetに因れば3.0〜5.5V のようです。

TO-92パッケージの商品をボードに置いたモジュールも確かに存在します。
DFROBOT社のDFR0024です。\900程度で入手出来るようです。

しかし リード付きの Waterproofモデルが使いやすいし、この18B20を使う意味を感じる次第です。DFROBOT社ではDFR0198という型番になります。

  • Red wire - VCC 、 Black wire - GND 、 Yellow wire - DATA
  • Usable with 3.0V to 5.5Vpower/data
  • ±0.5°CAccuracy from -10°C to +85°C
  • Usable temperature range: -55 to 125°C (-67°F to +257°F)
  • 9 to 12 bit selectable resolution
  • Uses 1-Wire interface- requires only one digital pin for communication
  • Unique 64 bit ID burned into the chip
  • Multiple sensors can share one pin
  • Temperature-limit alarm system
  • Query time is less than 750ms
  • Stainless steel tube 6mm diameter by 35mm long
  • Cable diameter: 4mm (0.16)
  • Length: 95cm (37.4")

Waterproofモデルとしてサーミスタをステンレス管に封印したモデルも実在します。
サーミスタのモデルは基本2芯なのですが、プルアップ抵抗を含めた3芯タイプも存在します。紛らわしいです。
注意が必要です。

Product ID: 381

Adaflurt社はWaterproof タイプのDS18B20に関し情報提供しているため、これを基準とします。DFR0198との違いはありますがセンサ自体は同じです。

18B20には64bitのIDdataが用意されています。そのうち48bitがシリアルナンバに相当します。シリアルナンバチェックすれば同じデータラインに複数の温度計測を実施することが可能です。

マイコンとの接続ですがデジタルピンを入力/出力切り替えてデータビットの送受信を行う事で温度取得します。

基本的なデータの遣り取りはArduinoのライブラリに任せるのがリーズナブルです。ただ、電気的な特性だけは意識しておく必要があります。

分解能等はコマンドにて設定する必要があります。デフォルトは12bitです。また、12bitの場合、変換時間に750msec必要です。そのため、12bit分解能の場合、サンプリングレートは1[S/s]程度です。また、複数のデバイスが同じラインに接続されていれば、デバイス毎に1秒占有となりますので、2ch取得なら0.5[S/s]と云う事になります。高速なサンプリングには不向きですが、扱いやすいと考えます。

温度データのフォーマットは以下の通りです。

分解能の設定次第でbit0..2の値が不確定かどうかの違いです。判りやすいです。

一つのラインに複数デバイスを載せた場合は、シリアル番号チェックして温度取得することになり多少効率が悪くなるかと思います。その点デバイス毎にデジタルピンを割り付けると効率は良くなりますが、プログラミング方法は要検討です。
アマゾンではWaterproofモデルが複数台セット販売されており、複数台の同時使用は当たり前と云えます。

1ラインにどの程度の18B20デバイスが接続出来るかですが、Pullupの抵抗値や、電源ラインの供給容量、或いは温度データ取得間隔等を鑑みて判断することになるのかと思います。
先人によると10基のデータ取得に苦心したという記事も見かけました。
データ取得ピンを独立させ並列取得出来るかという試みは見かけないです。なかなか難しいかもしれませんね。順番にPINを指定してデータ取得する分には問題無いと思われますし、デバイス指定が不要なのでパフォーマンスの低下も最小限に抑えられそうです。


STM32miniShieldと2基の18B20を接続して、LED&KEYに表示するスケッチを作成しました。

このコードを実行するに当たり追加が必要なライブラリは、

OneWireライブラリは新しいバージョンでないとRP2040に対応出来ていない様です

/*
 * 2023/08/15 T.Wanibe
 * 1.6.11 修正点:
 *      Operating Timeの表示にバグがあり修正
 *      一時間毎の温度管理をその時間の平均値表示がうまく出来ていないので修正
 * 1.6.10 修正点:
 *      Operating Timeの表示を改良
 *      NTP更新 更新タイミングを見直す。
 *      一時間毎の温度管理をその時間の平均値に変更する。
 * 1.6.9 修正点:
 *      時刻合わせのタイミングを1時間毎の温度計測タイミングとした
 *      グラフレンジを0−50に変更
 *      実行時間の秒表示が実際の倍の値というバグを修正した
 * 1.6.8 修正点:
 *       1.6.7では-60分問題が解決できていません。見直します。
 * 1.6.7 修正点:
 *      時刻表示が-60分という意味不明のバグになった.このことからNTP同期のタイミングを見直す
 * 1.6.6 修正点:
 *      時刻表示が-30分という意味不明のバグがまだ改善しない。もう一度時刻表示コードを見直す
 *      checkNTP()の実行タイミングに確かに問題があった タイマ割込のインターバルを500msecに変更した点を反映していなかった
 * 1.6.5 修正点:
 *      1.6.4で時刻表示が-30分という意味不明のバグがあったので、もう一度時刻表示コードを見直す
 *      ブラウザ表示で[Return]ボタンを追加
 *      lED&kEYのコールがMainLoopと割込Loopでバッティングしているので割込Loopのみに見直す
 * 1.6.4 修正点:
 *      時刻表示の改善が無かったので別の手段を試みた
 *      やはりタイマ割込を導入して1秒毎の更新となるように変更 ※温度計測はタイマ割込にすると処理時間の問題が出るのでメインループで実行する。
 * 1.6.3 修正点:
        時刻表示が1時間ずれるときがある。演算方法に問題があるようなので、他のコードからこの機能分を移植し直す
 * 1.6.2 修正点:
 *      経過時間表示がオーバフローしてしまう問題を修正
 *      IP設定画面の入力枠内を右寄せ表示に修正
 * 1.6.0 修正点:
 *      毎分の温度変化をグラフ表示出来る様に修正したいと考えました。setup3
 * 1.5.1 修正点:
 *      コードに無駄があったので修正した。接続デバイス数はsetup()内で自動判別するのが良いと思い変更
 * 1.5.0 修正点:
 *      ダミー計測をすることで値が0.0になることはなくなったが、2つのDS18B20を取り違えて計測してしまう事があり、連続性に問題がある。
 *      コードを変更してsetup()時に接続されているDS18B20のindexListを取得し、計測時にIDが合致するデータ列を意識するように変更した 
 * 1.4.2 修正点:
 *      計測前にdelayは効果無し 結果を見る限り定期的に三時間毎に0.0になっているので、ダミー計測を試すことにした。
 * 1.4.1 修正点:
 *      ch1のDS18B20のデータ取得に失敗するケースの対策が不十分 よく判らないが、計測前にdelayを入れてみる
 * 1.4.0 修正点:
 *      一時間毎のデータで0と云う値が出ている。これはおかしい。データ取得に失敗している。
 *      2ch目では発生していないことから、データ取得時待ち時間を置いてからデータ取得するように修正 
 *コメント
 *      DS18B20をブラウザ表示するソフトウエアコードを書いているのですが、03までのスケッチは期待通りに動作しません。
 *      時刻同期がなぜか失敗することが問題です。
 *      そこでベースとなるコードを変更して、機能追加し実現してみることにしました。
 *      以下はオリジナルコードのコメントです。
 *      このコードはEthernet3のExample“Udp NTP Client”をSTM32MINIShieldで動く様にレタッチしました。.
 *      BluePillにはRTCが搭載されていますが、精度が悪くバックアップ電源もありません。※接続は可能です
 *      そこで起動時にNTPで時刻所得して登録し、LED&KEYに時刻表示します。
 *      以後毎秒時刻更新します。
 *      1時間毎にNTPにアクセスして時刻調整します。
 *      Michael Margolis氏が2010年9月4日に作成したモノをレタッチしています。
 * 最大131072バイトのフラッシュメモリのうち、スケッチが56560バイト(43%)を使っています。
 * 最大20480バイトのRAMのうち、グローバル変数が4576バイト(22%)を使っていて、ローカル変数で15904バイト使うことができます。
 */
#include <libmaple/iwdg.h>
#include <SPI.h>
#include <Ethernet3.h>
#include <EthernetUdp3.h>
#include <TM1638.h>
#include <RTClock.h>
#include <EEPROM.h>
#include <avr/pgmspace.h>
#include <TextFinder.h>                                                 //WebSetting
#include <OneWire.h>                                                    //DS18B20通信用ライブラリ
//#include <DallasTemperature.h>
//PIN
#define W550io_Rst      PA8                                             //NIC_Reset
#define SPI1_NSS_PIN    PA4                                             //NIC_ChipSelec
#define UpdateInterval  86400                                           //更新間隔
#define dataPin         PB4
#define clockPin        PB3
#define strobePin       PA15
#define BUILTIN_LED     PC13
#define DS18B20Port     PA10
#define LED1            PB8
#define LED2            PB9
#define HttpPort        80                                              //HTTP
#define debug           1
#define iwdg_init_ms(N) iwdg_init(IWDG_PRE_256,((N)/8))                 //設定時間をmsecとするためにマクロを用意する。
#define vers            "STM32miniShield DS18B20 1.6"
#define NTP_PACKET_SIZE 48
#define SECS_PER_HOUR   3600
#define maxDevices      10
//コントローラのMACアドレスを以下に入力してください。
//新しいイーサネットシールドには、シールドのステッカーにMACアドレスが印刷されています
const char      FVirsion[]      = "1.6.11";
byte            mac[]           = {0x00,0x08,0xDC,0x54,0x4D,0xD1};      //Wiznet
byte            ip[]            = {192, 168, 0, 205};
byte            dns_server[]    = {192, 168, 0, 1};
byte            gateway[]       = {0, 0, 0, 0};
byte            subnet[]        = {255, 255, 255, 0};
byte            timeServer[]    = {192,168,0,199}; 
byte            packetBuffer[ NTP_PACKET_SIZE];                         //着信および発信パケットを保持するバッファ
byte            keys,lastKey;
//
unsigned int    localPort       = 8888;                                 //UDPパケットをリッスンするローカルポート
char            STRBUF[32];
char            buffer[128];
int             timeZone        = 9;                                    // change to your timezone
//オブジェクトコンストラクタ
EthernetServer  webServer(HttpPort);
EthernetClient  client;
RTClock rtclock (RTCSEL_LSE);                                           //RTC初期化
EthernetUDP     Udp;                                                    //UDPを介してパケットを送受信できるようにするUDPインスタンス
tm_t            tmm,tmm1;
TM1638          LedAndKey(dataPin, clockPin, strobePin);                //データピンPB4、クロックピンPB3、およびストローブピンPA15でモジュールを定義する
const byte      ID = 0x9B;
char            buf1[32];
char            buf2[32];
char            MacAddressStr[20];
char            IPAddressStr[20];
char            SubnetMaskStr[20];
char            GatewayStr[20];
char            NTPserverStr[20];
char            DateTimeStr[20];
String          DateStr;
String          TimeStr;
float           gDayBuf[24][4];                                         //24時間分4要素データ確保
float           gHourBuf[60][4];                                        //24時間分4要素データ確保
unsigned long   OperatingTime   = 0;                                    //稼働時間 Count2で1秒
OneWire         ds(PA10);                                               // on pin 10 (a 4.7K resistor is necessary)
boolean         fDoneTime       = false;
int             wdgTime         = 40000;
int             devNum          = maxDevices;                           //DS18B20の接続数 初期値は2としておきます。 メモリ確保のため
byte            gDS[maxDevices][8];
byte            h;                                                      //返値0-23
byte            m;                                                      //返値0-59
byte            dot             = 0;
unsigned long   DispTime;
int             preHSet          = -1;
int             preMSet         = -1;
int             Temp1,Temp2;
//----------------------------------
void LANSetup(){
        int idcheck = EEPROM.read(0);
        if (idcheck != ID){
                //idがIDの値ではない場合、
                //このスケッチがシールドを設定する前に使用されていなかったことを意味します
                //スケッチの始めに書かれた値を使用するだけです
        }
        if (idcheck == ID){
                //idがIDと同じ値の場合、
                //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                //EERPOMの値を読み取ってシールドを設定します。
                for (int i = 0; i < 6; i++){
                        mac[i] = EEPROM.read(i+1);
                }
                for (int i = 0; i < 4; i++){
                        ip[i] = EEPROM.read(i+7);
                }
                for (int i = 0; i < 4; i++){
                        subnet[i] = EEPROM.read(i+11);
                }
                for (int i = 0; i < 4; i++){
                        gateway[i] = EEPROM.read(i+15);
                }
                //アクセスNTPサーバー
                for (int i = 0; i < 4; i++){
                        timeServer[i] = EEPROM.read(i+19);
                }
        }
        sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
        sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]);
        sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]);
        sprintf(NTPserverStr,"%d.%d.%d.%d",timeServer[0],timeServer[1],timeServer[2],timeServer[3]);
        Ethernet.begin(mac, ip);
}
//--------------------------
void SetWebPage( EthernetClient client){
        client.println(F("HTTP/1.1 200 OK"));
        client.println(F("Content-Type: text/html"));
        client.println();
        //
        client.print(F("<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=UTF-8\">\n"));
        client.print(F("\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>"));
        client.print(vers);
        client.print(F(" Setup Page</TITLE>\n"));
        client.print(F("\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n"));
        client.print(F("\t<style type=\"text/css\">\n\t\t.tbox-style{\n\t\t\tpadding-top   : 4px;\n\t\t\tpadding-right : 4px;\n\t\t\tpadding-bottom: 2px;\n\t\t\ttext-align    : right;\n\t\t}\n\t</style>\n</HEAD>\n"));
        client.print(F("<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\">\n<BLOCKQUOTE><BLOCKQUOTE>\n"));
        client.print(F("<table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\">\n"));
        client.print(F("<tr><td>"));
        client.print(vers);
        client.print(F(" Setup Page</td></tr></table><br>\n"));
        //
        client.print(F("<script>\n\tfunction hex2num (s_hex) {\n\t\teval(\"var n_num=0X\" + s_hex);\n\t\treturn n_num;\n\t}\n</script>\n"));
        client.print(F("<tbody>\n<FORM><input type=\"hidden\" name=\"SBM\" value=\"1\">\n<table>\n<tr><td>MAC:</td><td>"));
        client.print(F("<input id=\"T1\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT1\" value=\""));
        client.print(mac[0],HEX);
        client.print(F("\" class=\"tbox-style\">.<input id=\"T3\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT2\" value=\""));
        client.print(mac[1],HEX);
        client.print(F("\" class=\"tbox-style\">.<input id=\"T5\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT3\" value=\""));
        client.print(mac[2],HEX);
        client.print(F("\" class=\"tbox-style\">.<input id=\"T7\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT4\" value=\""));
        client.print(mac[3],HEX);
        client.print(F("\" class=\"tbox-style\">.<input id=\"T9\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT5\" value=\""));
        client.print(mac[4],HEX);
        client.print(F("\" class=\"tbox-style\">.<input id=\"T11\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT6\" value=\""));
        client.print(mac[5],HEX);
        //
        client.print(F("\" class=\"tbox-style\"><input id=\"T2\" type=\"hidden\" name=\"DT1\"><input id=\"T4\" type=\"hidden\" name=\"DT2"));
        client.print(F("\"><input id=\"T6\" type=\"hidden\" name=\"DT3\"><input id=\"T8\" type=\"hidden\" name=\"DT4"));
        client.print(F("\"><input id=\"T10\" type=\"hidden\" name=\"DT5\"><input id=\"T12\" type=\"hidden\" name=\"DT6"));
        client.print(F("\"></td></tr>\n<tr><td>IP:</td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT7\" value=\""));
        client.print(ip[0],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT8\" value=\""));
        client.print(ip[1],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT9\" value=\""));
        client.print(ip[2],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT10\" value=\""));
        client.print(ip[3],DEC);
        //
        client.print(F("\" class=\"tbox-style\"></td></tr>\n<tr><td>MASK: </td><td><input type= \"text\" size=\"3\" maxlength=\"3\" name=\"DT11\" value=\""));
        client.print(subnet[0],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT12\" value=\""));
        client.print(subnet[1],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT13\" value=\""));
        client.print(subnet[2],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT14\" value=\""));
        client.print(subnet[3],DEC);
        //
        client.print(F("\" class=\"tbox-style\"></td></tr>\n<tr><td>GW: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT15\" value=\""));
        client.print(gateway[0],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT16\" value=\""));
        client.print(gateway[1],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT17\" value=\""));
        client.print(gateway[2],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT18\" value=\""));
        client.print(gateway[3],DEC);
        //
        //client.print(F("\"></td></tr>\n<tr><td><br></td COLSPAN='2'>\n<HR ALIGN=LEFT>"));
        client.print(F("\" class=\"tbox-style\"></td></tr><tr><td COLSPAN='2'>\n<HR ALIGN=CENTER></td><td>"));                      //1行空けたい
        //
        client.print(F("</td></tr><tr><td>NTPd: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT19\" value=\""));
        client.print(timeServer[0],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT20\" value=\""));
        client.print(timeServer[1],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT21\" value=\""));
        client.print(timeServer[2],DEC);
        client.print(F("\" class=\"tbox-style\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT22\" value=\""));
        client.print(timeServer[3],DEC);
        client.print(F("\" class=\"tbox-style\"></td></tr>\n<tr><td><br></td></tr><tr><td COLSPAN='2'><P ALIGN=RIGHT><INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://"));
        client.print(IPAddressStr);
        client.print(F("/setup9')\"/><input id=\"button1\"type=\"submit\" value=\"SUBMIT\" "));
        //
        client.print(F("Onclick=\""));
        client.print(F("document.getElementById('T2').value      = hex2num(document.getElementById('T1').value);\n"));
        client.print(F("\t\tdocument.getElementById('T4').value  = hex2num(document.getElementById('T3').value);\n"));
        client.print(F("\t\tdocument.getElementById('T6').value  = hex2num(document.getElementById('T5').value);\n"));
        client.print(F("\t\tdocument.getElementById('T8').value  = hex2num(document.getElementById('T7').value);\n"));
        client.print(F("\t\tdocument.getElementById('T10').value = hex2num(document.getElementById('T9').value);\n"));
        client.print(F("\t\tdocument.getElementById('T12').value = hex2num(document.getElementById('T11').value);\""));
        //
        client.print(F("></td></tr></tbody>\n</table>\n</BLOCKQUOTE></BLOCKQUOTE>\n</form>\n</BODY>\n</html>\n"));
}
//-------------------------- 2021/8/12
void SetPage1Day( EthernetClient client){
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        //
        client.print(F("<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=\"UTF-8\">\n"));
        client.print(F("\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>"));
        client.print(vers);
        client.print(F(" Utility Page</TITLE>\n"));
        client.print(F("\t<script type='application/javascript' SRC='http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js'></script>\n"));
        client.print(F("\t<script type='application/javascript' SRC='./setup3'></script>\n"));
        client.print(F("\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n"));
        client.print(F("\t<style>\n\t\tcanvas{\n"));
        client.print(F("\t\t\t-moz-user-select: none;\n"));
        client.print(F("\t\t\t-webkit-user-select: none;\n"));
        client.print(F("\t\t\t-ms-user-select: none;\n\t\t}\n"));
        client.print(F("\t\thtml { font-family: Helvetica; display: inline-block; margin: 0px auto;}\n"));
        client.print(F("\t\tbody{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n"));
        client.print(F("\t\tp {font-size: 24px;color: #444444;margin-bottom: 10px;}\n"));
        client.print(F("\t</style>\n</HEAD>\n"));
        client.print(F("<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\" BGCOLOR=\"#ffffff\">\n"));
        client.print(F("<FORM>\n<BLOCKQUOTE><BLOCKQUOTE>\n"));
        client.print(F("<P><table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\" CELLSPACING=\"2\">\n"));
        client.print(F("<tr><td>"));
        client.print(vers);
        client.print(F(" Utility Page</td></tr></table><br>\n"));
        //
        client.print(F("<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" style=\"table-layout: fixed\">"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">&nbsp;</TD><TD WIDTH=\"20%\">&nbsp;</TD><TD WIDTH=\"55%\"><P ALIGN=CENTER><INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://"));
        client.print(IPAddressStr);
        client.print(F("/setup9')\"/></TD>\n<TR>\n\t<TD WIDTH=\"25%\">FirmwareVirsion:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(FVirsion);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">MacAddress:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(MacAddressStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">IPAddress:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(IPAddressStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">SubnetMask:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(SubnetMaskStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\" NOWRAP>Data acquisition time(Local):</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(DateTimeStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\" NOWRAP>Num of connected sensors:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(devNum);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\" NOWRAP>Operating Time:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        //sprintf(buf2,"%ld[sec]",OperatingTime / 2);
        sprintf(buf2,"%ld[sec] (%d[day]%d[hour]:%d[min])",OperatingTime/2,OperatingTime/172800,(OperatingTime/7200)%24,(OperatingTime/120)%60);
        client.print(buf2);
        client.print(F("</TD>\n</TR></TABLE></P>\n"));
        client.print(F("\t<div style='width:75%;'><canvas id='canvas' width='750' height='400' style='display: block; width: 750px; height: 400px;'></canvas></div>\n"));
        client.print(F("</CENTER></BLOCKQUOTE></BLOCKQUOTE>\n</form>\n"));
        client.print(F("<script>\n"));
        client.print(F("\t\tvar randomScalingFactor = function() {\n\t\t\treturn 18 + Math.random() * 10;\n\t\t};\n"));
        client.print(F("\t\tvar data_00 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][0]) ? String('\0') : String(gDayBuf[i][0],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_01 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][1]) ? String('\0') : String(gDayBuf[i][1],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_02 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][2]) ? String('\0') : String(gDayBuf[i][2],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_03 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][3]) ? String('\0') : String(gDayBuf[i][3],2));
                client.print(F(","));
        }
        client.print(F("];\n"));        
        client.print(F("\t\tvar config = {"));
        client.print(F("\t\t\ttype: 'line',\n\t\t\tdata: {\n"));
        client.print(F("\t\t\t\tlabels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12' , '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],\n"));
        client.print(F("\t\t\t\tdatasets: [{\n"));
        client.print(F("\t\t\t\t\tlabel: '温度1[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_00,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.red,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tcubicInterpolationMode: 'monotone',\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y1'\n"));
        client.print(F("\t\t\t\t}, {\n"));
        client.print(F("\t\t\t\t\tlabel: '温度2[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_01,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.blue,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y2'\n"));
        client.print(F("\t\t\t\t}, {\n"));
        client.print(F("\t\t\t\t\tlabel: '温度3[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_02,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.orange,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y3'\n"));
        client.print(F("\t\t\t\t}, {\n"));
        client.print(F("\t\t\t\t\tlabel: '温度4[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_03,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.yellow,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y4'\n"));
        client.print(F("\t\t\t\t}]\n\t\t\t},\n"));
        client.print(F("\t\t\toptions: {\n\t\t\t\tresponsive: true,\n"));
        client.print(F("\t\t\t\ttitle: {\n\t\t\t\t\tdisplay: true,\n\t\t\t\t\ttext: '温度取得履歴'\n\t\t\t\t},\n"));
        client.print(F("\t\t\t\tlegend: {\n\t\t\t\t\tdisplay: true\n\t\t\t\t},\n"));
        client.print(F("\t\t\t\ttooltips: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tmode: 'index'\n\t\t\t\t},\n"));
        client.print(F("\t\t\t\tscales: {\n\t\t\t\t\txAxes: [{\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '時刻 [時]'\n\t\t\t\t\t\t}\n\t\t\t\t\t}],\n"));
        client.print(F("\t\t\t\t\tyAxes: [{\n\t\t\t\t\t\tid:'y1',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度1[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t}\n"));
        client.print(F("\t\t\t\t\t},{\n\t\t\t\t\t\tid:'y2',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度2[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t}\n"));
        client.print(F("\t\t\t\t\t},{\n\t\t\t\t\t\tid:'y3',\n\t\t\t\t\t\tposition: 'right',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度3[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t\t}\n"));
        client.print(F("\t\t\t\t\t},{\n\t\t\t\t\t\tid:'y4',\n\t\t\t\t\t\tposition: 'right',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度4[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}],\n"));
        client.print(F("\t\t\t\t}\n\t\t\t}\n\t\t};\n")); 
        client.print(F("\t\twindow.onload = function() {\n\t\t\tvar ctx = document.getElementById('canvas').getContext('2d');\n"));
        client.print(F("\t\t\twindow.myLine = new Chart(ctx, config);\n\t\t};\n"));
        client.print(F("</script>\n"));
        client.print(F("</BODY></html>"));
}
//-------------------------- 2022/2/18
void SetPage1Hour( EthernetClient client){
        client.println("HTTP/1.1 200 OK\nContent-Type: text/html\n\n");
        //client.println("Content-Type: text/html");
        //client.println();
        //
        client.print(F("<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=\"UTF-8\">\n\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>"));
        //client.print(F("\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>"));
        client.print(vers);
        client.print(F(" Utility Page</TITLE>\n\t<script type='application/javascript' SRC='http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js'></script>\n\t<script type='application/javascript' SRC='./setup3'></script>\n"));
        client.print(F("\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n"));
        //client.print(F("\t<script type='application/javascript' SRC='http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js'></script>\n"));
        //client.print(F("\t<script type='application/javascript' SRC='./setup3'></script>\n"));
        client.print(F("\t<style>\n\t\tcanvas{\n"));
        client.print(F("\t\t\t-moz-user-select: none;\n"));
        client.print(F("\t\t\t-webkit-user-select: none;\n"));
        client.print(F("\t\t\t-ms-user-select: none;\n\t\t}\n"));
        client.print(F("\t\thtml { font-family: Helvetica; display: inline-block; margin: 0px auto;}\n"));
        client.print(F("\t\tbody{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n"));
        client.print(F("\t\tp {font-size: 24px;color: #444444;margin-bottom: 10px;}\n"));
        client.print(F("\t</style>\n</HEAD>\n"));
        client.print(F("<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\" BGCOLOR=\"#ffffff\">\n"));
        client.print(F("<FORM>\n<BLOCKQUOTE><BLOCKQUOTE>\n"));
        client.print(F("<P><table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\" CELLSPACING=\"2\">\n"));
        client.print(F("<tr><td>"));
        client.print(vers);
        client.print(F(" Utility Page</td></tr></table><br>\n"));
        //
        client.print(F("<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\" style=\"table-layout: fixed\">"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">&nbsp;</TD><TD WIDTH=\"20%\">&nbsp;</TD><TD WIDTH=\"55%\"><P ALIGN=CENTER><INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://"));
        client.print(IPAddressStr);
        client.print(F("/setup9')\"/></TD>\n<TR>\n\t<TD WIDTH=\"25%\">FirmwareVirsion:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(FVirsion);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">MacAddress:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(MacAddressStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">IPAddress:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(IPAddressStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\">SubnetMask:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(SubnetMaskStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\" NOWRAP>Data acquisition time(Local):</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(DateTimeStr);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\" NOWRAP>Num of connected sensors:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        client.print(devNum);
        client.print(F("</TD>\n</TR>"));
        client.print(F("<TR>\n\t<TD WIDTH=\"25%\" NOWRAP>Operating Time:</TD>\n\t<TD WIDTH=\"20%\"></TD>\n\t<TD WIDTH=\"55%\">"));
        //sprintf(buf2,"%ld[sec]",OperatingTime / 2);
        //sprintf(buf2,"%ld[sec] (%d[day]%d[hour]:%d[min])",OperatingTime/2,OperatingTime/172800,OperatingTime/7200,OperatingTime/120);
        sprintf(buf2,"%ld[sec] (%d[day]%d[hour]:%d[min])",OperatingTime/2,OperatingTime/172800,(OperatingTime/7200)%24,(OperatingTime/120)%60);
        client.print(buf2);
        client.print(F("</TD>\n</TR></TABLE></P>\n"));
        client.print(F("\t<div style='width:75%;'><canvas id='canvas' width='750' height='400' style='display: block; width: 750px; height: 400px;'></canvas></div>\n"));
        client.print(F("</CENTER></BLOCKQUOTE></BLOCKQUOTE>\n</form>\n"));
        client.print(F("<script>\n"));
        client.print(F("\t\tvar randomScalingFactor = function() {\n\t\t\treturn 18 + Math.random() * 10;\n\t\t};\n"));
        client.print(F("\t\tvar data_00 = ["));
        for(int i = 0; i<60 ;i++){
                client.print(isnan(gHourBuf[i][0]) ? String('\0') : String(gHourBuf[i][0],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_01 = ["));
        for(int i = 0; i<60 ;i++){
                client.print(isnan(gHourBuf[i][1]) ? String('\0') : String(gHourBuf[i][1],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_02 = ["));
        for(int i = 0; i<60 ;i++){
                client.print(isnan(gHourBuf[i][2]) ? String('\0') : String(gHourBuf[i][2],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_03 = ["));
        for(int i = 0; i<60 ;i++){
                client.print(isnan(gHourBuf[i][3]) ? String('\0') : String(gHourBuf[i][3],2));
                client.print(F(","));
        }
        client.print(F("];\n"));        
        client.print(F("\t\tvar config = {"));
        client.print(F("\t\t\ttype: 'line',\n\t\t\tdata: {\n"));
        client.print(F("\t\t\t\tlabels: ['0', '', '2', '', '4', '', '6', '', '8', '', '10', '', '12' , '', '14', '', '16', '', '18', '', '20', '', '22', '', '24', '', '26', '', '28', '', '30', '', '32' , '', '34', '', '36', '', '38', '', '40', '', '42', '', '44', '', '46', '', '48', '', '50', '', '52' , '', '54', '', '56', '', '', '59'],\n"));
        client.print(F("\t\t\t\tdatasets: [{\n"));
        client.print(F("\t\t\t\t\tlabel: '温度1[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_00,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.red,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tcubicInterpolationMode: 'monotone',\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y1'\n"));
        client.print(F("\t\t\t\t}, {\n"));
        client.print(F("\t\t\t\t\tlabel: '温度2[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_01,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.blue,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y2'\n"));
        client.print(F("\t\t\t\t}, {\n"));
        client.print(F("\t\t\t\t\tlabel: '温度3[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_02,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.orange,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y3'\n"));
        client.print(F("\t\t\t\t}, {\n"));
        client.print(F("\t\t\t\t\tlabel: '温度4[℃]',\n"));
        client.print(F("\t\t\t\t\tdata: data_03,\n"));
        client.print(F("\t\t\t\t\tborderColor: window.chartColors.yellow,\n"));
        client.print(F("\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"));
        client.print(F("\t\t\t\t\tfill: false,\n"));
        client.print(F("\t\t\t\t\tyAxisID: 'y4'\n"));
        client.print(F("\t\t\t\t}]\n\t\t\t},\n"));
        client.print(F("\t\t\toptions: {\n\t\t\t\tresponsive: true,\n"));
        client.print(F("\t\t\t\ttitle: {\n\t\t\t\t\tdisplay: true,\n\t\t\t\t\ttext: '温度取得履歴'\n\t\t\t\t},\n"));
        client.print(F("\t\t\t\tlegend: {\n\t\t\t\t\tdisplay: true\n\t\t\t\t},\n"));
        client.print(F("\t\t\t\ttooltips: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tmode: 'index'\n\t\t\t\t},\n"));
        client.print(F("\t\t\t\tscales: {\n\t\t\t\t\txAxes: [{\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '時刻 [分]'\n\t\t\t\t\t\t}\n\t\t\t\t\t}],\n"));
        client.print(F("\t\t\t\t\tyAxes: [{\n\t\t\t\t\t\tid:'y1',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度1[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t}\n"));
        client.print(F("\t\t\t\t\t},{\n\t\t\t\t\t\tid:'y2',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度2[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t}\n"));
        client.print(F("\t\t\t\t\t},{\n\t\t\t\t\t\tid:'y3',\n\t\t\t\t\t\tposition: 'right',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度3[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t\t}\n"));
        client.print(F("\t\t\t\t\t},{\n\t\t\t\t\t\tid:'y4',\n\t\t\t\t\t\tposition: 'right',\n\t\t\t\t\t\tdisplay: true,\n"));
        client.print(F("\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"));
        client.print(F("\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\tlabelString: '温度4[℃]'\n\t\t\t\t\t\t},\n"));
        client.print(F("\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"));
        client.print(F("\t\t\t\t\t\t\tsuggestedMin: 0,\n\t\t\t\t\t\t\tsuggestedMax:  50\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}],\n"));
        client.print(F("\t\t\t\t}\n\t\t\t}\n\t\t};\n")); 
        client.print(F("\t\twindow.onload = function() {\n\t\t\tvar ctx = document.getElementById('canvas').getContext('2d');\n"));
        client.print(F("\t\t\twindow.myLine = new Chart(ctx, config);\n\t\t};\n"));
        client.print(F("</script>\n"));
        client.print(F("</BODY></html>"));
}
//--------------------------
void checkWebPage( EthernetClient client)
{
        Serial.println(F("new webClient"));
        boolean restart = false;
        if (client) {
                TextFinder  finder(client );
                while (client.connected()) {
                        //digitalWrite(LED, HIGH);
                        if (client.available()) {
                                //この部分はすべてのテキスト検索を行います。
                                if( finder.find("GET /") ) {
                                        // 「setup」とい語が見つかった場合は、さらに探してください。
                                        // その単語が見つからない場合は、検索を停止して先に進みます。
                                        // これにより、後でスケッチに独自のWebページを配置できます。
                                        if (finder.findUntil("setup", "\n\r")){
                                                long cord = finder.getValue();
                                                sprintf(buf1,"setupIn=%d",cord);
                                                Serial.println(buf1);
                                                switch(cord){
                                                        case 1:
                                                                // 「SBM」という単語が見つかった場合は、さらに探し続けます。
                                                                // その言葉が見つからない場合は、探して停止します。
                                                                // SUBMITボタンが押されていない、何も押されていないことを意味します
                                                                // セットアップページが構築されている場所に移動し、クライアントのブラウザに表示します。
                                                                if (finder.findUntil("SBM", "\n\r")){
                                                                        byte SET = finder.getValue();
                                                                        // これで、「DT」という文字を探している間に、「DT」の後ろにあるすべての数字を覚えて、
                                                                        // 値を一致させて、mac、ip、subnet、およびgatewayに入れる必要があります。
                                                                        while(finder.findUntil("DT", "\n\r")){
                                                                                int val = finder.getValue();
                                                                                // 「DT」のvalが1?6の場合、対応する値はMAC値でなければなりません。
                                                                                if(val >= 1 && val <= 6) {
                                                                                        mac[val - 1] = finder.getValue();
                                                                                }
                                                                                // 「DT」のvalが7?10の場合、対応する値はIP値でなければなりません。
                                                                                if(val >= 7 && val <= 10) {
                                                                                        ip[val - 7] = finder.getValue();
                                                                                }
                                                                                // 「DT」のvalが11?14の場合、対応する値はMASK値でなければなりません。
                                                                                if(val >= 11 && val <= 14) {
                                                                                        subnet[val - 11] = finder.getValue();
                                                                                }
                                                                                // 「DT」のvalが15?18の場合、対応する値はGW値でなければなりません。
                                                                                if(val >= 15 && val <= 18) {
                                                                                        gateway[val - 15] = finder.getValue();
                                                                                }  
                                                                                // 「DT」のvalが19?22の場合、対応する値はTimeServer値でなければなりません。
                                                                                if(val >= 19 && val <= 22) {
                                                                                        timeServer[val - 19] = finder.getValue();
                                                                                }
                                                                        }
                                                                        // すべてのデータを取得したので、EEPROMに保存できます
                                                                        for (int i = 0 ; i < 6; i++){
                                                                                EEPROM.write(i + 1,mac[i]);
                                                                        }
                                                                        for (int i = 0 ; i < 4; i++){
                                                                                EEPROM.write(i + 7, ip[i]);
                                                                        }
                                                                        for (int i = 0 ; i < 4; i++){
                                                                                EEPROM.write(i + 11, subnet[i]);
                                                                        }
                                                                        for (int i = 0 ; i < 4; i++){
                                                                                EEPROM.write(i + 15, gateway[i]);
                                                                        }
                                                                        for (int i = 0 ; i < 4; i++){
                                                                                EEPROM.write(i + 19, timeServer[i]);
                                                                        }
                                                                        // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。
                                                                        EEPROM.write(0, ID);
                                                                        sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
                                                                        sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
                                                                        sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]);
                                                                        sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]);
                                                                        // すべてのデータがEEPROMに書き込まれている場合、arduinoをリセットする必要があります。
                                                                        //ハードウェアリセットボタンを使用する必要があります。
                                                                        restart = true;
                                                                }else{
                                                                        
                                                                }
                                                                // この時点から、セットアップページの構築を開始し、クライアントのブラウザーに表示できます。
                                                                SetWebPage(client);
                                                                break;
                                                        case 2:
                                                                // 新規にユーティリティ頁を作りました。
                                                                Serial.println(F("SetPage1Day"));
                                                                rtclock.getTime(tmm);
                                                                sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",tmm.year+1970, tmm.month, tmm.day,tmm.hour, tmm.minute, tmm.second);
                                                                SetPage1Day(client);
                                                                break;
                                                        case 3:
                                                                //utils.jsが要求された。
                                                                Serial.println(F("utils.js"));
                                                                LoadUtilsJS(client);
                                                                break;
                                                        case 4:
                                                                //新規に一時間分の分単位グラフ表示を作りました
                                                                Serial.println(F("SetPage1Hour"));
                                                                rtclock.getTime(tmm);
                                                                sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",tmm.year+1970, tmm.month, tmm.day,tmm.hour, tmm.minute, tmm.second);
                                                                SetPage1Hour(client);
                                                                break;
                                                       case 9:
                                                                //トップページに戻る方法として追加しました。
                                                                Serial.println(F("Home"));
                                                                pageIntroduction(client);
                                                                break;
                                                        default:
                                                                PrintResponse404(client );
                                                                break;   
                                                }
                                        }else{
                                              pageIntroduction(client);  
                                        }
                                }
                                break;
                        }
                        PrintResponse404(client );
                }
                delay(1);
                client.stop();
                if(restart)     nvic_sys_reset();
        }     
}
//----------------------------2022年2月18日メニュー追加 2023年7月11日レタッチ
void pageIntroduction( EthernetClient client){
        client.println(F("HTTP/1.1 200 OK\nContent-Type: text/html\n\n"));
        //client.println(F("Content-Type: text/html"));
        //client.println();
        // put your own html from here on
        sprintf(buf1,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        client.println(F("<HTML>\n<HEAD>\n\t<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=UTF-8\">\n</HEAD>\n<BODY BGCOLOR='#ffffff'>\n<H2><CENTER><FONT COLOR='#00ff00'>DS18B20 SetUp Menu</FONT></CENTER></H2>\n<P><CENTER><TABLE WIDTH='500' BORDER='0' CELLSPACING='0' CELLPADDING='0'>\n\t<TR>\n\t\t<TD WIDTH='100%'>\n\t\t<OL>\n"));
        //client.println(F("<BODY BGCOLOR='#ffffff'>\n<H2><CENTER><FONT COLOR='#00ff00'>DS18B20 SetUp Menu</FONT></CENTER></H2>\n"));
        //client.println(F("<P><CENTER><TABLE WIDTH='500' BORDER='0' CELLSPACING='0' CELLPADDING='0'>\n\t<TR>\n\t\t<TD WIDTH='100%'>\n\t\t<OL>\n"));
        sprintf(buffer,"\t\t\t<LI><FONT SIZE='+1'><A HREF=\"http://%s/setup1\">設定メニュー</A>\n",buf1);
        client.println(buffer);
        sprintf(buffer,"\t\t\t<LI><A HREF=\"http://%s/setup2\">温度履歴表示 時単位(最近一日)</A>\n",buf1);
        client.println(buffer);
        sprintf(buffer,"\t\t\t<LI><A HREF=\"http://%s/setup4\">温度履歴表示 分単位(最近一時間)</A></FONT>\n",buf1);
        client.println(buffer);
        client.print(F("\t\t</OL>\n\t\t</TD>\n\t</TR>\n</TABLE></CENTER>\n</BODY>\n</HTML>\n"));
        client.stop();
}
//--------------------------
void PrintResponse404( EthernetClient client )
{
        client.println(F("HTTP/1.1 404 Not Found\nContent-Type: text/html\nConnnection: close\n\n"));
        //client.println(F("Content-Type: text/html"));
        //client.println(F("Connnection: close")); 
        //client.println();
        client.stop();
}
//--------------------------
void LoadUtilsJS( EthernetClient client ){                              //2023/07/11 少しでも纏めてみた。
        client.println("HTTP/1.1 200 OK\nContent-Type: text/html\n\n");
        //client.println("Content-Type: text");
        //client.println();
        //
        client.println("'use strict';\nwindow.chartColors = {\n\tred: 'rgb(255, 99, 132)',\n\torange: 'rgb(255, 159, 64)',\n\tyellow: 'rgb(255, 205, 86)',\n\tgreen: 'rgb(75, 192, 192)',\n\tblue: 'rgb(54, 162, 235)',\npurple: 'rgb(153, 102, 255)',\n\tgrey: 'rgb(201, 203, 207)'\n};\n");
        //
        //client.println("window.chartColors = {");
        //client.println("\tred: 'rgb(255, 99, 132)',");
        //client.println("\torange: 'rgb(255, 159, 64)',");
        //client.println("\tyellow: 'rgb(255, 205, 86)',");
        //client.println("\tgreen: 'rgb(75, 192, 192)',");
        //client.println("\tblue: 'rgb(54, 162, 235)',");
        //client.println("\tpurple: 'rgb(153, 102, 255)',");
        //client.println("\tgrey: 'rgb(201, 203, 207)'");
        //client.println("};\n");
        //
        client.println("(function(global) {\n\tvar MONTHS = [\n\t\t'January',\n\t\t'February',\n\t\t'March',\n\t\t'April',\n\t\t'May',\n\t\t'June',\n\t\t'July',\n\t\t'August',\n\t\t'September',\n\t\t'October',\n\t\t'November',\n\t\t'December'\n\t];\n");
        //client.println("\tvar MONTHS = [");
        //client.println("\t\t'January',");
        //client.println("\t\t'February',");
        //client.println("\t\t'March',");
        //client.println("\t\t'April',");
        //client.println("\t\t'May',");
        //client.println("\t\t'June',");
        //client.println("\t\t'July',");
        //client.println("\t\t'August',");
        //client.println("\t\t'September',");
        //client.println("\t\t'October',");
        //client.println("\t\t'November',");
        //client.println("\t\t'December'");
        //client.println("\t];\n");
        //
        client.println("\tvar COLORS = [\n\t\t'#4dc9f6',\n\t\t'#f67019',\n\t\t'#f53794',\n\t\t'#537bc4',\n\t\t'#acc236',\n\t\t'#166a8f',\n\t\t'#00a950',\n\t\t'#58595b',\n\t\t'#8549ba'\n\t];\n");
        //client.println("\t\t'#4dc9f6',");
        //client.println("\t\t'#f67019',");
        //client.println("\t\t'#f53794',");
        //client.println("\t\t'#537bc4',");
        //client.println("\t\t'#acc236',");
        //client.println("\t\t'#166a8f',");
        //client.println("\t\t'#00a950',");
        //client.println("\t\t'#58595b',");
        //client.println("\t\t'#8549ba'");
        //client.println("\t];\n");
        //
        client.println("\tvar Samples = global.Samples || (global.Samples = {});\n\tvar Color = Chart.helpers.color;\n");
        //client.println("\tvar Color = Chart.helpers.color;\n");
        //
        client.println("\tfunction applyDefaultNumbers(config) {\n\t\tvar cfg = config || {};\n\t\tcfg.min = cfg.min || 0;\n\t\tcfg.max = cfg.max || 1;\n\t\tcfg.from = cfg.from || [];\n\t\tcfg.count = cfg.count || 8;\n\t\tcfg.decimals = cfg.decimals || 8;\n\t\tcfg.continuity = cfg.continuity || 1;\n");
        //client.println("\t\tvar cfg = config || {};");
        //client.println("\t\tcfg.min = cfg.min || 0;");
        //client.println("\t\tcfg.max = cfg.max || 1;");
        //client.println("\t\tcfg.from = cfg.from || [];");
        //client.println("\t\tcfg.count = cfg.count || 8;");
        //client.println("\t\tcfg.decimals = cfg.decimals || 8;");
        //client.println("\t\tcfg.continuity = cfg.continuity || 1;\n");
        //
        client.println("\t\treturn cfg;\n\t}\n");
        //client.println("\t}\n");
        //
        client.println("\tSamples.utils = {\n\t\t// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/\n\t\tsrand: function(seed) {\n\t\t\tthis._seed = seed;\n\t\t},\n");
        //client.println("\t\t// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/");
        //client.println("\t\tsrand: function(seed) {");
        //client.println("\t\t\tthis._seed = seed;");
        //client.println("\t\t},\n");
        //
        client.println("\t\trand: function(min, max) {\n\t\t\tvar seed = this._seed;\n\t\t\tmin = min === undefined ? 0 : min;\n\t\t\tmax = max === undefined ? 1 : max;\n\t\t\tthis._seed = (seed * 9301 + 49297) % 233280;\n\t\t\treturn min + (this._seed / 233280) * (max - min);\n\t\t},\n");
        //client.println("\t\t\tvar seed = this._seed;");
        //client.println("\t\t\tmin = min === undefined ? 0 : min;");
        //client.println("\t\t\tmax = max === undefined ? 1 : max;");
        //client.println("\t\t\tthis._seed = (seed * 9301 + 49297) % 233280;");
        //client.println("\t\t\treturn min + (this._seed / 233280) * (max - min);");
        //client.println("\t\t},\n");
        //
        client.println("\t\tnumbers: function(config) {\n\t\t\tvar cfg = applyDefaultNumbers(config);\n\t\t\tvar dfactor = Math.pow(10, cfg.decimals) || 0;\n\t\t\tvar data = [];\n\t\t\tvar i, value;\n");
        //client.println("\t\t\tvar cfg = applyDefaultNumbers(config);");
        //client.println("\t\t\tvar dfactor = Math.pow(10, cfg.decimals) || 0;");
        //client.println("\t\t\tvar data = [];");
        //client.println("\t\t\tvar i, value;\n");
        //
        client.println("\t\t\tfor (i = 0; i < cfg.count; ++i) {\n\t\t\t\tvalue = (cfg.from[i] || 0) + this.rand(cfg.min, cfg.max);\n\t\t\t\tif (this.rand() <= cfg.continuity) {\n\t\t\t\t\tdata.push(Math.round(dfactor * value) / dfactor);\n\t\t\t\t} else {\n\t\t\t\t\tdata.push(null);\n\t\t\t\t}\n\t\t\t}\n");
        //client.println("\t\t\t\tvalue = (cfg.from[i] || 0) + this.rand(cfg.min, cfg.max);");
        //client.println("\t\t\t\tif (this.rand() <= cfg.continuity) {");
        //client.println("\t\t\t\t\tdata.push(Math.round(dfactor * value) / dfactor);");
        //client.println("\t\t\t\t} else {");
        //client.println("\t\t\t\t\tdata.push(null);");
        //client.println("\t\t\t\t}");
        //client.println("\t\t\t}\n");
        //
        client.println("\t\t\treturn data;\n\t\t},\n");
        //client.println("\t\t},\n");
        //
        client.println("\t\tlabels: function(config) {\n\t\t\tvar cfg = config || {};\n\t\t\tvar min = cfg.min || 0;\n\t\t\tvar max = cfg.max || 100;\n\t\t\tvar count = cfg.count || 8;\n\t\t\tvar step = (max - min) / count;\n\t\t\tvar decimals = cfg.decimals || 8;\n\t\t\tvar dfactor = Math.pow(10, decimals) || 0;\n\t\t\tvar prefix = cfg.prefix || '';\n\t\t\tvar values = [];\n\t\t\tvar i;\n");
        //client.println("\t\t\tvar cfg = config || {};");
        //client.println("\t\t\tvar min = cfg.min || 0;");
        //client.println("\t\t\tvar max = cfg.max || 100;");
        //client.println("\t\t\tvar count = cfg.count || 8;");
        //client.println("\t\t\tvar step = (max - min) / count;");
        //client.println("\t\t\tvar decimals = cfg.decimals || 8;");
        //client.println("\t\t\tvar dfactor = Math.pow(10, decimals) || 0;");
        //client.println("\t\t\tvar prefix = cfg.prefix || '';");
        //client.println("\t\t\tvar values = [];");
        //client.println("\t\t\tvar i;\n");
        //
        client.println("\t\t\tfor (i = min; i < max; i += step) {\n\t\t\t\tvalues.push(prefix + Math.round(dfactor * i) / dfactor);\n\t\t\t}\n");
        //client.println("\t\t\t\tvalues.push(prefix + Math.round(dfactor * i) / dfactor);");
        //client.println("\t\t\t}\n");
        //
        client.println("\t\t\treturn values;\n\t\t},\n");
        //client.println("\t\t},\n");
        //
        client.println("\t\tmonths: function(config) {\n\t\t\tvar cfg = config || {};\n\t\t\tvar count = cfg.count || 12;\n\t\t\tvar section = cfg.section;\n\t\t\tvar values = [];\n\t\t\tvar i, value;\n");
        //client.println("\t\t\tvar cfg = config || {};");
        //client.println("\t\t\tvar count = cfg.count || 12;");
        //client.println("\t\t\tvar section = cfg.section;");
        //client.println("\t\t\tvar values = [];");
        //client.println("\t\t\tvar i, value;\n");
        //
        client.println("\t\t\tfor (i = 0; i < count; ++i) {\n\t\t\t\tvalue = MONTHS[Math.ceil(i) % 12];\n\t\t\t\tvalues.push(value.substring(0, section));\n\t\t\t}\n");
        //client.println("\t\t\t\tvalue = MONTHS[Math.ceil(i) % 12];");
        //client.println("\t\t\t\tvalues.push(value.substring(0, section));");
        //client.println("\t\t\t}\n");
        //
        client.println("\t\t\treturn values;\n\t\t},\n");
        //client.println("\t\t},\n");
        //
        client.println("\t\tcolor: function(index) {\n\t\t\treturn COLORS[index % COLORS.length];\n\t\t},\n");
        //client.println("\t\t\treturn COLORS[index % COLORS.length];");
        //client.println("\t\t},\n");
        //
        client.println("\t\ttransparentize: function(color, opacity) {\n\t\t\tvar alpha = opacity === undefined ? 0.5 : 1 - opacity;\n\t\t\treturn Color(color).alpha(alpha).rgbString();\n\t\t}\n\t};\n");
        //client.println("\t\t\tvar alpha = opacity === undefined ? 0.5 : 1 - opacity;");
        //client.println("\t\t\treturn Color(color).alpha(alpha).rgbString();");
        //client.println("\t\t}");
        //client.println("\t};\n");
        //
        client.println("\t// DEPRECATED\n\twindow.randomScalingFactor = function() {\n\t\treturn Math.round(Samples.utils.rand(-100, 100));\n\t};\n");
        //client.println("\twindow.randomScalingFactor = function() {");
        //client.println("\t\treturn Math.round(Samples.utils.rand(-100, 100));");
        //client.println("\t};\n");
        //
        client.println("\t// INITIALIZATION\n\n\tSamples.utils.srand(Date.now());\n");
        //
        //client.println("\tSamples.utils.srand(Date.now());\n");
        //
        client.println("\t// Google Analytics\n\t/* eslint-disable */\n\tif (document.location.hostname.match(/^(www\\.)?chartjs\\.org$/)) {\n\t\t(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n\t\t(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n\t\tm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n\t\t})(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n\t\tga('create', 'UA-28909194-3', 'auto')\n\t\tga('send', 'pageview');\n\t}\n\t/* eslint-enable */\n");
        //client.println("\t/* eslint-disable */");
        //client.println("\tif (document.location.hostname.match(/^(www\\.)?chartjs\\.org$/)) {");
        //client.println("\t\t(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){");
        //client.println("\t\t(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),");
        //client.println("\t\tm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)");
        //client.println("\t\t})(window,document,'script','//www.google-analytics.com/analytics.js','ga');");
        //client.println("\t\tga('create', 'UA-28909194-3', 'auto');");
        //client.println("\t\tga('send', 'pageview');");
        //client.println("\t}");
        //client.println("\t/* eslint-enable */\n");
        //
        client.println("}(this));");
}
//-------指定されたアドレスのタイムサーバーにNTP要求を送信します
void    sendNTPpacket(byte address[]){
        memset(packetBuffer, 0, NTP_PACKET_SIZE);               //バッファ内のすべてのバイトを0に設定します
        //NTP要求を形成するために必要な値を初期化する
        packetBuffer[0]         = 0b11100011;                   // LI, Version, Mode
        packetBuffer[1]         = 0;                            //階層、またはクロックのタイプ
        packetBuffer[2]         = 6;                            //ポーリング間隔
        packetBuffer[3]         = 0xEC;                         //ピアクロックの精度
        //ルート遅延およびルート分散用のゼロの8バイト
        packetBuffer[12]        = 49;
        packetBuffer[13]        = 0x4E;
        packetBuffer[14]        = 49;
        packetBuffer[15]        = 52;
        //すべてのNTPフィールドに値が与えられました。
        //タイムスタンプを要求するパケットを送信できます:
        Udp.beginPacket(address, 123);                          //NTPリクエストはポート123へ
        Udp.write(packetBuffer, NTP_PACKET_SIZE);
        Udp.endPacket();
}
//-----------------     割込CallBack      修正2023/07/12 500msec毎に呼び出され、表示更新する様にした。
void TimeUpdate(void){
        //500msec毎に呼ばれる
        OperatingTime++;
        if(OperatingTime%2)     dot     =       0b00010000;
        else                    dot     =       0b00000100;
        //時刻チェック
        rtclock.getTime(tmm);
        h = tmm.hour;                           //返値0-23
        m = tmm.minute;                         //返値0-59
        //
        if(lastKey != 0){
                switch(lastKey){
                        case 0x01:                                      //温度1を表示
                                Temp1 = int(gHourBuf[preMSet][0]  * 100.0);
                                LedAndKey.setDisplayToDecNumber(Temp1,0b00000100,false);
                                break;
                        case 0x02:                                      //温度2を表示
                                Temp2 = int(gHourBuf[preMSet][1]  * 100.0);
                                LedAndKey.setDisplayToDecNumber(Temp2,0b00000100,false);
                                break;
                        default:                                        //時刻表示
                                //
                                DispTime    =       h*10000 + m*100 + tmm.second;
                                LedAndKey.setDisplayToDecNumber(DispTime,dot,false);
                                break;
                }
        }
        if(preMSet != m){        //2023/8/15 シーケンスをちょっと変更 時間温度の平均化
                
                //1分おきにデータ取込
                preMSet  = m;
                float   celsius;
                //本計測
                for (int i = 0;i<devNum;i++){
                        GetDSTemp(celsius,i);
                        if(celsius != 0.0){
                              gHourBuf[m][i]    =       celsius;  
                        }
                }
                //次回分のデータをNULL化
                m = (m+1) % 60;
                for (int i = 0;i<devNum;i++){
                         gHourBuf[m][i]         =       NAN;
                }
                if(!fDoneTime){
//                      fDoneTime               = checkNTP();
                }                
        }else if(preHSet != h){
                //1時間おきに時刻を確認し、データをメモリに確保
                preHSet          =       h;
                //本計測
                for (int i = 0;i<devNum;i++){
                        float   celsius =       0.0;
                        float   count   =       0.0;
                        //GetDSTemp(celsius,i);
                        //if(celsius != 0.0){
                        //     gDayBuf[h][i]   =       celsius;  
                        //}
                        int k = preMSet+1;
                        for (int j = 0; j<k; j++){
                                if(gHourBuf[j][i] != NAN){
                                        celsius = celsius + gHourBuf[j][i];
                                        count   = count + 1.0;
                                }
                        }
                        if(count)       gDayBuf[h][i] = celsius / count;
                }
                //次回分のデータをNULL化
                h = (h+1) % 24;
                for (int i = 0;i<devNum;i++){
                         gDayBuf[h][i]   =       NAN;
                }
                //NTP更新 2023/08/12 更新タイミングを見直す。
                if(preMSet == 10){
                        fDoneTime               = checkNTP();
                }
        }else{
                //計測しない
        }
        keys    = LedAndKey.getButtons();
        if(keys != 0){
                lastKey = keys;
                LedAndKey.setLEDs(lastKey);
        }
}
//------------------
bool SetDSDevice(int index) {
        byte i;
        byte present = 0;
        byte type_s;
        byte data[12];
        byte addr[8];
        //float celsius;
        if ( !ds.search(addr)) {
                Serial.println(F("No more addresses."));
                ds.reset_search();
                delay(100);
                return false;
        }else{
                memcpy(gDS[index], addr, sizeof(addr));
                return true;
        }
}
//------------------
void GetDSTemp(float &celsius,int index) {
        byte i;
        byte present = 0;
        byte type_s;
        byte data[12];
        byte addr[8];
        //float celsius;
        /* 検索不要
        for (int i;i<devNum;i++){
                ds.search(addr);
                if(memcmp(addr, gDS[i], sizeof(addr)) == 0)     break;
        }
        ds.reset_search();
        */
        if (OneWire::crc8(gDS[index], 7) != gDS[index][7]) {
                Serial.println(F("CRC is not valid!"));
                return;
        }
        // 最初のROMバイトはチップ種を示します
        switch (gDS[index][0]) {
                case 0x10:
                        Serial.println(F("  Chip = DS18S20"));          // or old DS1820
                        type_s = 1;
                        break;
                case 0x28:
                        Serial.println(F("  Chip = DS18B20"));
                        type_s = 0;
                        break;
                case 0x22:
                        Serial.println(F("  Chip = DS1822"));
                        type_s = 0;
                        break;
                default:
                        Serial.println(F("Device is not a DS18x20 family device."));
                        return;
        }
        ds.reset();
        ds.select(gDS[index]);
        ds.write(0x44, 1);                              // 最後に寄生物の電源を入れて、変換を開始します
        delay(750);                                     // 多分750msで十分かもしれません12bit分解能の場合
        // ここでds.depower()を実行する場合がありますが、リセットによって処理されます。
        present = ds.reset();
        ds.select(gDS[index]);    
        ds.write(0xBE);                                 // スクラッチパッドを読む
        //Serial.print(F("  Data = "));
        //Serial.print(present, HEX);
        //Serial.print(F(" "));
        for ( i = 0; i < 9; i++) {                      // we need 9 bytes
                data[i] = ds.read();
                //Serial.print(data[i], HEX);
                //Serial.print(F(" "));
        }
        //Serial.print(F(" CRC="));
        //Serial.print(OneWire::crc8(data, 8), HEX);
        //Serial.println();
        //結果は16ビットの符号付き整数であるため、データを実際の温度に変換します。
        //データは「int16_t」タイプに格納する必要があります。
        //これは、32ビットプロセッサでコンパイルした場合でも常に16ビットです。
        int16_t raw = (data[1] << 8) | data[0];
        if (type_s) {
                raw = raw << 3;                         // デフォルトの9ビット解像度
                if (data[7] == 0x10) {                  // 「残り数」は完全な12ビットの解像度を提供します
                        raw = (raw & 0xFFF0) + 12 - data[6];
                }
        } else {
                byte cfg = (data[4] & 0x60);
                // 低解像度では、下位ビットは未定義なので、ゼロにしましょう
                if (cfg == 0x00) raw = raw & ~7;        // 9ビットの解像度、93.75ミリ秒
                else if (cfg == 0x20) raw = raw & ~3;   // 10ビットの解像度、187.5ミリ秒
                else if (cfg == 0x40) raw = raw & ~1;   // 11ビットの解像度、375ミリ秒
                // デフォルトは12ビットの解像度、750ミリ秒の変換時間です
        }
        celsius = (float)raw / 16.0;
        //fahrenheit = celsius * 1.8 + 32.0;
        Serial.print(F("  Temperature = "));    Serial.println(celsius);
        return;
}
//-----------------
int     getHourTime(void){
        rtclock.getTime(tmm1);
        return tmm1.hour;
}
//-----------------
int     getMinuteTime(void){
        rtclock.getTime(tmm1);
        return tmm1.minute;
}
//----------------
bool checkNTP(){
        sendNTPpacket(timeServer);                              //NTPパケットをタイムサーバーに送信する
        delay(300);                                            //返信が利用可能かどうかを確認するのを待ちます
        if ( Udp.parsePacket() ) {
                //パケットを受信し、そこからデータを読み取ります
                Udp.read(packetBuffer, NTP_PACKET_SIZE);        //パケットをバッファに読み込みます
                //タイムスタンプは、受信したパケットのバイト40から始まり、4バイト、つまり2ワードの長さです。
                unsigned long secsSince1900;
                // convert four bytes starting at location 40 to a long integer
                secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
                secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
                secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
                secsSince1900 |= (unsigned long)packetBuffer[43];
                unsigned long epoch   = secsSince1900 - 2208988800UL + (timeZone * SECS_PER_HOUR);
                rtclock.setTime(time_t(epoch));                 //JSTを内部時計にセット
                rtclock.getTime(tmm1);
                /*
                Serial.print((epoch  % 86400L) / 3600);         //時間を印刷します(86400は1日あたりの秒数に相当)
                Serial.print(':');
                int min = (epoch % 3600) / 60;
                if ( min < 10 ) {
                        Serial.print('0');                      //各時間の最初の10分では、先頭に「0」が必要です。
                }
                Serial.print(min);                              //分を印刷する(3600は1分あたりの秒数に等しい)
                Serial.print(':');
                int sec = epoch % 60;
                if ( sec < 10 ) {
                        Serial.print('0');                      //各分の最初の10秒で、先頭に「0」が必要になります
                }
                Serial.println(sec);                            //秒を印刷
                */
                return true;
        }else{
                return false;
        }
}
//----------------
void setup()
{
        // Open serial communications and wait for port to open:
        Serial.begin(115200);                                   //シリアル通信を開ます。
        pinMode(BUILTIN_LED,OUTPUT);    digitalWrite(BUILTIN_LED,LOW);
        pinMode(LED1,OUTPUT);           digitalWrite(LED1, HIGH);
        pinMode(LED2,OUTPUT);           digitalWrite(LED2, LOW);
        //Ethernet3API
        Ethernet.setCsPin(SPI1_NSS_PIN);
        Ethernet.setRstPin(W550io_Rst);
        pinMode(W550io_Rst, OUTPUT);
        digitalWrite(W550io_Rst, LOW);
        delay(10);
        digitalWrite(W550io_Rst, HIGH);
        Serial.print(F("NIC_Reset\n"));
        LANSetup();
        //イーサネットとUDPを開始します
        Udp.begin(localPort);
        Serial.print(F("server is at "));Serial.println(Ethernet.localIP());
        fDoneTime       = checkNTP();
        rtclock.getTime(tmm);
        sprintf(STRBUF,"%02u%02u%02u",tmm.hour,tmm.minute,tmm.second);
        LedAndKey.setDisplayToString(STRBUF,0b00010100,2);
        //LedAndKey.setDisplayToString("000000",0,2);
        Serial.print(F("server is at "));Serial.println(Ethernet.localIP());
        webServer.begin();
        //データバッファクリア
        for(int i = 0;i<24;i++){
                for(int j = 0;j<4;j++){
                        gDayBuf[i][j] = NAN;
                }
        }
        for(int i = 0;i<60;i++){
                for(int j = 0;j<4;j++){
                        gHourBuf[i][j] = NAN;
                }
        }
        //DS18B20の初期化
        for(int i = 0;i<10;i++){
                delay(1);
                if(!SetDSDevice(i)){
                        devNum = i;
                        break;
                }
        }
        //タイマ割込設定
        Timer1.pause();                                                 //
        Timer1.setPrescaleFactor(7200);                                 // 72MHz100uSEC
        Timer1.setOverflow(5000);                                       // 500mSEC
        Timer1.attachInterrupt(TIMER_UPDATE_INTERRUPT,TimeUpdate);      // 割り込みサーブルーチンの宣言:TimeUpdate
        Timer1.setCount(0);                                             // 0
        Timer1.refresh();
        Timer1.resume(); 
        //
        iwdg_init_ms(wdgTime);                                         //ウォッチドッグをオンにして、オーバーフロー時間を設定します。
        Serial.println(F("EndSetUp"));
}
//----------------
void loop()
{
        //このLoopはscantime=1秒程度です。そのため5秒経っても戻らなかったらリセットすることにします。
        iwdg_feed();                                                    //ウォッチドッグタイマーをリセットするには、ドッグ操作をフィードします
        //
        if(!((OperatingTime + 600) % 7200)){                            //1時間に一回
//                fDoneTime       = checkNTP();     
        }
        if(Serial){
                if(!(OperatingTime % 60))       Serial.println(F("."));
                else                            Serial.print(F("."));
        }
        //digitalWrite(BUILTIN_LED,OperatingTime % 2);
        client          = webServer.available();                        //HTTP要求確認
        if(client)      checkWebPage(client);
        client.stop();                                                  // コネクションを閉じる。
        if(!devNum){
                for(int i = 0;i<10;i++){
                        delay(1);
                        if(!SetDSDevice(i)){
                                devNum = i;
                                break;
                        }
                }
        }
        if(OperatingTime % 2){
                digitalWrite(LED1, LOW);
                digitalWrite(LED2, HIGH);
        }else{
                digitalWrite(LED1, HIGH);
                digitalWrite(LED2, LOW);
        }
        delay(200);
}

スケッチを修正して、W5500EVBPicoと2基の18B20を接続して、LED&KEYに表示するスケッチを構築しました。


戯言(nonsense)に戻る


問い合わせ頁の表示


免責事項

本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。

本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。

商標・登録商標

Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。