hiro yamamoto works

マイコンハード、ソフトを作ったりしています。
お家や現場のお困りごと解決に!
内容利用は自己責任でお願いします。

赤外線リモコンWi-Fi中継の応用 Webページからテレビを操作(設定ファイル読み2次元配列入れて)

2024-04-03 16:00:50 | 赤外線リモコン

スケッチ改変ポイントなどを説明してみようかと思いました。
間違い、文字化け、抜けがあるかもしれません。

素晴らしいライブラリ、サンプルスケッチを公開してくださっている方々に感謝します。

赤外線送信したいコントロール内容を、簡単テキストファイルでSDに保存しておきます。
"コントロール実行(赤外線送信)せよ"と命令来たら、読み込んで赤外線リモコン信号送信します。
#include "FS.h"
#include "SD.h"
#include "SPI.h"
中略
uint16_t IRco[20][5];
uint8_t NOIRCO = 0;//Number of IR control operations
中略
  if (!SD.begin(44)) { //XIAO ESP32S3 GPIO44/D7
    Serial.println("Card Mount Failed");
    return;
  }
void readFile(fs::FS &fs, const char * path) {
  Serial.printf("Reading file: %s\n", path);
  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }
//2次元配列の型とサイズ uint16_t IRco[20][5];//[行][列] 横書きフォーマット
  Serial.print("Read from file: ");
  while (file.available()) {
    //Serial.write(file.read());
    String line = file.readStringUntil('\n');//終端文字'\n'が検出されるまで読んで文字列全体をlineへ入れる
    line = line.substring(0, line.indexOf('#'));//インデックス0(行頭)から(#までのインデックス数)の文字列取得
    //uint8_t NOIRCO = 0;//設定ファイルでは省略してNCOとしました。コントロールの数 Number of IR control operations
    if (line.substring(0, 3) == "NCO") { //開始位置(0)は含むが終了位置(3)は含まれない
      String NCO = line.substring(4, 6);//String変数名も設定ファイルと同じNCOとしました。
      NCO.trim();//スペース等を除去
      NOIRCO = NCO.toInt();
      Serial.println("NOIRCO = ");
      Serial.println(NOIRCO);
    } else if (line.substring(0, 3) == "C00") { //開始位置(0)は含むが終了位置(3)は含まれない
      String command0_0 = line.substring(4, 8); //address
      command0_0.trim();//スペース等を除去
      IRco[0][0] = strtol(command0_0.c_str(), NULL, 16);//address uint16_t
      String command0_1 = line.substring(9, 11);//command uint8_t
      IRco[0][1] = strtol(command0_1.c_str(), NULL, 16);//.toInt();
      //repeatは2固定のようなので省略しようと思う
      String command0_2 = line.substring(12, 14);//Bit
      IRco[0][2] = command0_2.toInt();
      String command0_3 = line.substring(15, 20);//interval
      command0_3.trim();//スペース等を除去
      IRco[0][3] = command0_3.toInt();
    } else if (line.substring(0, 3) == "C01") {
中略
    } else if (line.substring(0, 3) == "C09") {
      String command9_0 = line.substring(4, 8); //address
      command9_0.trim();//スペース等を除去
      IRco[9][0] = strtol(command9_0.c_str(), NULL, 16);//address uint16_t
      String command9_1 = line.substring(9, 11);//command uint8_t
      IRco[9][1] = strtol(command9_1.c_str(), NULL, 16);//.toInt();
      String command9_2 = line.substring(12, 14);//Bit
      IRco[9][2] = command9_2.toInt();
      String command9_3 = line.substring(15, 20);//interval
      command9_3.trim();//スペース等を除去
      IRco[9][3] = command9_3.toInt();
    }
  }
  file.close();
中略
void loop() {
中略
//"SimpleWiFiServer"スケッチへの改変部分です
        //クライアントのリクエストが "GET /H "か "GET /L "かをチェックする:Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          //digitalWrite(5, HIGH); // GET /H turns the LED off
          /*ユーザー様の環境に合わせてカスタマイズできるように、
            SDメモリに赤外線コード、インターバル時間、送信順序を記述したファイルで設定する*/
          //sendSony()関数へ与える引数の型は次の通りです。
          //sendSony(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats,
          // uint8_t numberOfBits)
          /*備忘記 2次元配列 IRco[0][0] //uint8_t NOIRCO = ;*/
          CheckTVpower();//GPIO13がLOWの時TVがONしていると検出し"TV_Pon"を"1"にする
          //TV電源ONから開始するときはi=0、すでにONしている時はi=1とすれば良いのでは
          //TV電源ONのときTV_Ponは"1"
          for (uint8_t i = TV_Pon; i < NOIRCO; i++) { //Number of IR control operations
            //for (uint8_t i = 0; i < NOIRCO; i++) { //Number of IR control operations
            IrSender.sendSony(IRco[i][0], (uint8_t)IRco[i][1] , 2, IRco[i][2]); //POWER ON-OFF
            //POWER ONから次の操作を受け付けるまでの待ち時間
            delay(IRco[i][3]);
          }


関数 bool CheckTvpower()
//Check the TV power 電源がONしている時はONのコントロールを省略する7
bool CheckTVpower() {
  TV_Pon = !(digitalRead(TV_PowDet_PIN));//TVonのときLOW("0")なので反転して使う
  //uint8_t TV_Pon = 0;//"1"でTV電源がONしている
  //Serial.print("Check TV power = ");
  if (TV_Pon) {
    //Serial.println("ON");
    return 1;
  } else {
    //Serial.println("OFF");
    return 0;
  }
}


素人の書いたコードですが、少しでも参考になればと思います。
終わりかな


赤外線リモコンWi-Fi中継の応用 Webページからテレビを操作(WiFiMangerスケッチを改変したところなど)

2024-04-03 14:30:52 | 赤外線リモコン

スケッチ改変ポイントなどを説明してみようかと思いました。
間違い、文字化けがあるかもしれません。

素晴らしいライブラリ、サンプルスケッチを公開してくださっている方々に感謝します。

Wi-Fi接続と固定IPアドレス設定のために"WiFiManager"ライブラリの
"Advanced"サンプルスケッチで設定したIPAddress、Gateway、Subnetを
(Gatewey、Subnetは不要かもしれない)EEPROMへ保存している。
SSIDとPASSWORDは初回設定後引数指定せずにWiFi.begin();
としてESP32内部に保存された前回WiFi認証情報を使って接続する。

#define INI_SETUP_PIN 15 //ESP32 DEV Module INPUT_PULLUP
中略
EEPROMへのデータ保存準備
//>>> EEPROM put アドレスを指定する
//なぜかEEPROM_SSID_ADDRESS 0のデータだけ電源OFF-ONで化けるので使っていない
#define EEPROM_SSID_ADDRESS 0 //使っていないが削除して不具合が出ないか心配で残してある
#define EEPROM_PASS_ADDRESS 32 //使っていないが削除して不具合が出ないか心配で残してある
#define EEPROM_IP_ADDRESS   64
#define EEPROM_GATEWAY      96
#define EEPROM_SUBNET       128 // 1アドレスに1byte String savedSSID;//それぞれの情報が入る変数
String savedPassword;
IPAddress savedIP; //IPAddress型
IPAddress savedGateway;
IPAddress savedSubnet;
//<<< EEPROM PUT

  //>>>> EEPROM setup
  Serial.println("\nTesting EEPROM Library\n");
  if (!EEPROM.begin(512)) { //512byte
    Serial.println("Failed to initialise EEPROM");//"EEPROMの初期化に失敗しました"
    Serial.println("Restarting...");//再起動せずにLEDを高速点滅して停止
    delay(1000);
    Serial.println("stop...");
    while (1) {
      // LEDを高速点滅する
      digitalWrite(LED_BUILTIN, HIGH);
      delay(100);
      digitalWrite(LED_BUILTIN, LOW);
      delay(100);
    }
    //ESP.restart();//これで再起動もできますが、再起動で解決できないことが多いかも
  } else {
    Serial.println("EEPROM Library Test OK ");
  } //<<<< EEPROM setup

GPIO15がHIGHの時 EEPROMに保存したWiFi認証&IP情報で接続する。
GPIO15がLOWの時 強制的にconfigPortalを起動して設定&接続する。
if (digitalRead(INI_SETUP_PIN) == HIGH) { //GPIO15(INPUT_PULLUP)HIGHの時はEEPROMからGETした情報でWiFi接続する
    //LOWのときはconfigPortalを起動してWiFi認証、接続情報設定する
    Serial.println("Previous WiFi authentication and connection with IP address in EEPROM");
    //"以前のWiFi認証とEEPROM内のIPアドレスによる接続"
    eepromGetData(); // EEPROMから保存済のIPアドレスを各変数へ読み込む(WiFi認証情報は未使用)
    IPAddress dns1 = savedGateway;//dns1はGateweyと同じなので代入
    WiFi.config(savedIP, savedGateway, savedSubnet, dns1);//ESP 引数順序厳守 NTPサーバ名アクセス時dns1要
    WiFi.begin();// ESP32内部に保存された前回WiFi認証情報(SSID、PASSWORD)を使って接続する
    //>>> 2024.01.29     Serial.print("Connecting to WiFi");
    uint8_t i = 0;
    while (WiFi.status() != WL_CONNECTED && i++
      digitalWrite(LED_BUILTIN, HIGH);
      delay(250);
      digitalWrite(LED_BUILTIN, LOW);
      delay(250);
      //delay(500);
      Serial.print(i); //Serial.print(".");
    }/* while(WiFi.status() != WL_CONNECTED &&...*/
    //Serial.println(i);
    if (i >= 20) { //iが20以上の時はWiFi認証情報に問題があると思われるのでconfigPortalを起動して設定し直す
      Serial.println("Connection Failed!");
      //wm.resetSettings();// wipe settings
      //ESP.restart(); //ESP32を再起動
      //<<
      startConfigPortal();//configPortal起動 関数にしてみました
    } /*if (i >= 20)*/
  } else { //if (INI_SETUP_PIN == HIGH)//GPIO15がHIGHじゃない時     //>>>> WiFiManagerのconfigPortalで接続設定 //関数化する
    startConfigPortal();//configPortal起動 関数にしてみました   }


それぞれの関数は適切な位置へ挿入してください。
関数startConfigPortal()
configPortalの一部分を関数化したものです。
"WiFiManager"ライブラリの
"Advanced"サンプルスケッチの改変部分だけ記載しています。
void startConfigPortal() {
中略
  //set static ip固定IPアドレスをセットする ここに書いたアドレスがデフォルト設定として表示されます。
  wm.setSTAStaticIPConfig(IPAddress(192, 168, 2, 100), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0)); // set static ip,gw,sn
  中略
//bool res;
  // res = wm.autoConnect(); //chipidからAP名を自動生成 auto generated AP name from chipid
  // res = wm.autoConnect("AutoConnectAP"); //匿名AP anonymous ap
  //res = wm.autoConnect("AutoConnectAP","password"); //パスワードで保護されたAP password protected ap
  /*if(!res) { //戻り値が"false"接続失敗 (res = wm.autoConnect()使用時)
    Serial.println("Failed to connect or hit timeout");
    //ESP.restart();
    } else {
    //ここまで来れば、WiFiに接続したことになる。 if you get here you have connected to the WiFi
    Serial.println("connected...yeey :)??");
    }*/
  /*暫定的に無効化するため関数にして移動した*/
  // start portal w delay
  Serial.println("Starting config portal");
  wm.setConfigPortalTimeout(120);
  if (!wm.startConfigPortal("OnDemandAP", "password")) {
    Serial.println("failed to connect or hit timeout");
    delay(3000);
    // ESP.restart();
  } else {
    //if you get here you have connected to the WiFi
    Serial.println("now connected...yeey :)");
    eepromPutData();
//WiFi認証情報と静的IP設定を保存 関数名変更SaveConfigCallbackをeepromPutDataへ
  }
  eepromGetData(); // EEPROMから(保存済の?)WiFi認証とIPアドレスをそれぞれの変数へ読み込む
} //<<<


関数eepromGetData()
//EEPROMからWiFi認証(保存NGだった)とIPアドレスをそれぞれの変数へ読み込む
void eepromGetData() {
  //EEPROM.get(EEPROM_SSID_ADDRESS, savedSSID);//SSIDが電源ON-OFFで化けるため使用中止した
  //EEPROM.get(EEPROM_PASS_ADDRESS, savedPassword);//SSID、PASSWORDは設定すると記憶される基本的な機能を活用
  EEPROM.get(EEPROM_IP_ADDRESS, savedIP);
  EEPROM.get(EEPROM_GATEWAY, savedGateway);
  EEPROM.get(EEPROM_SUBNET, savedSubnet);
}


関数eepromPutData () は設定が終わったIPアドレスをESP32のEEPROMへ保存します。
WiFi認証情報の保存、読み出しはうまく行かなかった。
void eepromPutData () {
//関数名変更SaveConfigCallbackをeepromPutDataへ
  Serial.println("Save button pressed, saving WiFi credentials and static IP configuration...");
  //"保存ボタンが押され、WiFi認証情報と静的IP設定が保存されました..."
  EEPROM.put(EEPROM_SSID_ADDRESS, WiFi.SSID());//SSIDはEEPROM保存しているが使っていない
  EEPROM.put(EEPROM_PASS_ADDRESS, WiFi.psk());//PASSWORD(psk)はEEPROM保存しているが使っていない
  EEPROM.put(EEPROM_IP_ADDRESS, WiFi.localIP());
  EEPROM.put(EEPROM_GATEWAY, WiFi.gatewayIP());
  EEPROM.put(EEPROM_SUBNET, WiFi.subnetMask());
  EEPROM.commit();
}

だんだんわからんなってきた

つづく
"SimpleWiFiServer"
"IRremote"ライブラリの"SendRawDemo"
受信したデータを赤外線リモコン信号にしてテレビへ送信する