Quantcast
Channel: 日曜大工、DIY、Excel VBAのページ
Viewing all 83 articles
Browse latest View live

ESP12E+BME280, 温度グラフ

$
0
0
キーワード: ソースコード     esp8266    esp32  esp12  BME280  IoT    arduino    jQuery   PHP   chart.js

目的

BME280で測定した温度をレンタルサーバーへ送り、PCやスマホからグラフを見る

イメージ 3


イメージ 1

イメージ 2

Sketch

.ino 以外のコードは https://blogs.yahoo.co.jp/pdxpopypop/65491778.html を見よ

/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor
  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2650
  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.
  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!
  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  2018/09/25
  Attention :  I2C address in Adafluit Library  --- Adafruit_BME280.h
  changed to     #define BME280_ADDRESS                (0x76)
 ***************************************************************************/
// http://shangtian.hatenablog.com/entry/2017/06/16/223755
// measure and chart update every 1 min
// BME280 test , 2018/9/25
#include <ESP8266WiFi.h>
#include  <WiFiClient.h>
const char* ssid = "D8*************G";
const char* password = "2************7";
// host name of server
#define HOST_NAME     "databooster.stars.ne.jp"
// file path of PHP file
#define PHP_PATH      "/shangtianblog10/sensorSet10.php"
// port number
#define PORT_NUMBER   80
float sigma = 0;
float average = 0;
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
unsigned long delayTime;

// host name of server
const char* server = "databooster.stars.ne.jp";
// WiFiClient instance
WiFiClient client;
// make connection to WiFi and server
void connectWiFi();
void connectServer();
void setup() {
    delay(1000);
    Serial.begin(115200);
    delay(500);
    Serial.println();
    Serial.println(F("BME280 test"));
    bool status;
   
    // default settings
    // (you can also pass in a Wire library object like &Wire2)
    status = bme.begin(); 
    if (!status) {
        Serial.println("Could not find a valid BME280 sensor, check wiring!");
        while (1);
    }
   
    Serial.println("-- Default Test --");
    Serial.println();
 
     connectWiFi();
}
#define MILLISECONDS_TO_WAIT 60000
unsigned long time_zero = millis();
void loop() {
  printValues();
  // delay(500);
  time_zero = millis();
 
  // read analog input
  int analogOUT = 0;
  int count = 0;
  sigma = 0;
  average = 0;
  while (count < 100) {
    analogOUT = bme.readTemperature() -2.8;
    average = average + analogOUT;
    sigma = sigma + analogOUT * analogOUT;
    delay(400);
    count++;
  }
 
  average = average / count;
  Serial.println ( average );
  sigma = sqrt( sigma / count - average * average );
  // end analog read
  connectServer();
  delay(10);
  if (millis() - time_zero < MILLISECONDS_TO_WAIT) {
       Serial.println ( MILLISECONDS_TO_WAIT - millis() + time_zero );   
       delay( MILLISECONDS_TO_WAIT - millis() + time_zero );
  }
}

// connection to WiFi
void connectWiFi() {
  Serial.println();
  Serial.println();
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  // wait till WiFi be connected
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }
  Serial.println ( "" );
  Serial.print ( "Connected to " );
  Serial.println ( ssid );
}
// send data to server
void connectServer() {
  int analogOUT = 0;
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    char s[16];
    dtostrf(average, 3, 1, s);
    char sendData[300] = "";
    sprintf(sendData, "GET %s?value=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", PHP_PATH, s, HOST_NAME);
    Serial.println(sendData);
    client.println(sendData);
    Serial.println("********  Closed  **********");
  }
}
void printValues() {
    Serial.print("Temperature = ");
    Serial.print(bme.readTemperature() -2.8 );
    Serial.println(" deg");
    Serial.print("Pressure = ");
    Serial.print(bme.readPressure() / 100.0F + 39 );
    Serial.println(" hPa");
    // Serial.print("Approx. Altitude = ");
    // Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
    // Serial.println(" m");
    Serial.print("Humidity = ");
    Serial.print(bme.readHumidity() + 5);
    Serial.println(" %");
    Serial.println();
}

ESP12E+ CdS, 照度グラフ

$
0
0


Purpose

display two parameters on one chart 

Result : chart created by chart.js

Blue line is voltage between CdS and Resistor ,  and  those average of 100 times for 1 min.
Orange line is  standard deviation of those 100 voltages for 1 min.

Below is a chart  when I came home and turned on lights.
During the 1 min , when light was turned on , standard deviation is large.

As a result , the IoT system works very well.
It costs
 - ESP12E    \700
 - rental server \120 / month --- very cheep , but PHP is available.
 - CdS and resister , circuit boad and other  \800
 - USB cable  \700     ---  very hiegh quality USB cable in order to prevent writing error of sketch.
 - software   ---  all free , arduino IDE , library ,  jQuery
 -  total   \2,320

Skill
  Arduino IDE similar to C++ ,   Javascript ,   chart.js  ,  PHP , HTML

イメージ 1

Javascript code to display two parameters by using chart.js


// http://databooster.stars.ne.jp/shangtianblog20/index.html
// index20.js
// sensor_to_server20.ino
// reference and helpful web-site to create this sketch
//  --> https://blog.goo.ne.jp/xmldtp/e/95890e6dd83d76d601b66513bf3f1993
var TEMPERATURE_DATA_URL = "../shangtianblog20/sensorLog20.txt";
// 表示する行数
const num_X = 30;
// センサーの値
var sensorValue = 0;
var timeMes = "";
// サーバーにアクセス中かどうか
var isAjax = false;
var ctx = document.getElementById("chart").getContext("2d");
var data = {
     labels: [],

     // corresponds to datasets[0]  ,  datasets[1]
     datasets: [
         {

             label: "CdS",
             fill: false,
             lineTension: 0.1,
             backgroundColor: "rgba(75,192,192,0.4)",
             borderColor: "rgb(5,141,199)",
             borderCapStyle: 'butt',
             borderDash: [],
             borderDashOffset: 0.0,
             borderJoinStyle: 'miter',
             pointBorderColor: "rgb(5,141,199)",
             pointBackgroundColor: "#fff",
             pointBorderWidth: 1,
             pointHoverRadius: 3,
             pointHoverBackgroundColor: "rgba(75,192,192,1)",
             pointHoverBorderColor: "rgba(100,100,100,1)",
             pointHoverBorderWidth: 2,
             pointRadius: 5,
             pointHitRadius: 10,
             data: [],
             spanGaps: false,
         },
         {
             label: "sigma",
             fill: false,
             lineTension: 0.1,
             backgroundColor: "rgba(75,192,192,0.4)",
             borderColor: "rgb(199,141,5)",
             borderCapStyle: 'butt',
             borderDash: [],
             borderDashOffset: 0.0,
             borderJoinStyle: 'miter',
             pointBorderColor: "rgb(199,141,5)",
             pointBackgroundColor: "#fff",
             pointBorderWidth: 1,
             pointHoverRadius: 3,
             pointHoverBackgroundColor: "rgba(75,192,192,1)",
             pointHoverBorderColor: "rgba(100,100,100,1)",
             pointHoverBorderWidth: 2,
             pointRadius: 5,
             pointHitRadius: 10,
             data: [],
             spanGaps: false,
         }
     ]
 };

// グラフの描画設定
var options = {
  title:{
  display: true,
  text:"CdS, ESP12E/Wifi/starserver,PHP/chart.js ver20",
  fontSize: 20,
  },

  // アニメーションの速さ
  animationSteps: 1,
  // 線をベジェ曲線で滑らかにするかどうか
//  bezierCurve: true,
  // Y軸方向のグリッドを表示するかどうか
  scaleShowVerticalLines: true,
  scales: {
    xAxes: [{
       gridLines:{
         color: "#8f8f8f",
       },
       ticks: {
         fontColor: "#aaa",
         fontSize: 16,
         // labelFontSize: 20,
         maxRotation: 90,
         minRotation: 90,
         autoSkip: true,
       },
    }],
    yAxes: [{
       gridLines:{
         color: "#5f5f5f",
       },
       ticks: {
         fontColor: "#aaa",
         fontSize: 16,
         beginAtZero:true,
         scaleStartValue: 0,
         max: 1000,
         stepSize: 100,
       },
    }]
  },
};
 
 var js_chart = new Chart(ctx, {
     type: 'line',
     data: data,
     options: options,
 });

  // サーバーへアクセス中でなければ
  isAjax = false;
  if(!isAjax) getSensorValue();
  // データ数がnum_X件超えたら古いデータを削除
  // http://frankzyj2010.blogspot.jp/2017/02/chartjs-v2-add-custom-legend-and.html
  var len = js_chart.data.labels.length;
  if (len > num_X) {
      // https://github.com/chartjs/Chart.js/issues/3507
      for(var ii = 0; ii < len - num_X ; ii++) {
        js_chart.data.labels.shift();
        js_chart.data.datasets.forEach(function(dataset){
          dataset.data.shift();
        });
      };
  };
  js_chart.update();

setInterval(function() {
  // サーバーへアクセス中でなければ
  isAjax = false;
  if(!isAjax) getSensorValue();
  // データ数がnum_X件超えたら古いデータを削除
  // http://frankzyj2010.blogspot.jp/2017/02/chartjs-v2-add-custom-legend-and.html
  var len = js_chart.data.labels.length;
  if (len > num_X) {
      // https://github.com/chartjs/Chart.js/issues/3507
      for(var ii = 0; ii < len - num_X ; ii++) {
        js_chart.data.labels.shift();
        js_chart.data.datasets.forEach(function(dataset){
          dataset.data.shift();
        });
      };
  };
  js_chart.update();
}, 60000);

function getSensorValue() {
  // フラグをtrue
  isAjax = true;
  $.ajax({
  // url: PHP_URL + "?p=" + new Date().getTime(),
    url: TEMPERATURE_DATA_URL,
    type: "post",
    dataType: "text",
    success: function(value) {
       // txtデータを配列に変換する
       var tempArray = value.split("\n");
       var numrow_value = tempArray.length;
       var csvArray = new Array();
       for(var i = 0; i< numrow_value ;i++){
          csvArray[i] = tempArray[i].split(",");
       };
       // グラフに値を描画
       // var len1 = 1; // js_chart.data.labels.length;
      
       for(var ii = Math.max(numrow_value - num_X - 1 , 0) ; ii < numrow_value - 1 ; ii++) {
               js_chart.data.labels[ii] = csvArray[ii][0];
               js_chart.data.datasets[0].data[ii] = csvArray[ii][1];
               js_chart.data.datasets[1].data[ii] = csvArray[ii][2];
       };

       
        // フラグをfalse
       isAjax = false;
    },
    error: function(){
      console.log("Ajax could not get Sensor Value from server");
      isAjax = false;
    }
  })
}

ESP12E, deep sleep

$
0
0

目的

ソーラーセル付きのモバイルバッテリーでESP12Eを永久に駆動させたい。
イメージ 4

ESP12Eの発熱が小さくなるので、温度、湿度センサーをESP12Eと同じ容器に収納できる。

結果 グラフ


イメージ 3

ポイント

配線
RSTとD0(GPIO16) を結線する
イメージ 1

イメージ 2

Sketch
deep sleep からさめると、sketchの最初から実行する。
つまり、 loop の中で、これより下の行は無視される

Sketch

// sensor_to_server30.ino

// reference  http://shangtian.hatenablog.com/entry/2017/06/16/223755
#include <ESP8266WiFi.h>
#include  <WiFiClient.h>
const char* ssid = "D*******G";
const char* password = "2********7";
// host name of server
#define HOST_NAME     "databooster.stars.ne.jp"
// file path of PHP file
#define PHP_PATH      "/shangtianblog30/sensorSet30.php"
// port number
#define PORT_NUMBER   80
float sigma = 0;
float average = 0;
// host name of server
const char* server = "databooster.stars.ne.jp";
// WiFiClient instance
WiFiClient client;
// make connection to WiFi and server
void connectWiFi();
void connectServer();
void setup() {
  // connection to PC with serial communication (RS232C)
  Serial.begin(115200);
  connectWiFi();
}
#define MILLISECONDS_TO_WAIT 60000
unsigned long time_zero = millis();
void loop() {
  time_zero = millis();
 
  // read analog input
  int analogOUT = 0;
  int count = 0;
  sigma = 0;
  average = 0;
  while (count < 5) {
    analogOUT = analogRead(A0);
    average = average + analogOUT;
    sigma = sigma + analogOUT * analogOUT;
    delay(400);
    count++;
  }
  average = average / count;
  Serial.println ( average );
  sigma = sqrt( sigma / count - average * average );
  // end analog read
  connectServer();
  delay(10);

  //DEEP SLEEPモード突入命令
  Serial.println("DEEP SLEEP START!!");
  //1:μ秒での復帰までのタイマー時間設定  2:復帰するきっかけの設定(モード設定)
  ESP.deepSleep(51 * 1000 * 1000 , WAKE_RF_DEFAULT);
  //deepsleepモード移行までのダミー命令
  delay(1000);

  return ;
}
// connection to WiFi
void connectWiFi() {
  Serial.println();
  Serial.println();
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  // wait till WiFi be connected
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }
  Serial.println ( "" );
  Serial.print ( "Connected to " );
  Serial.println ( ssid );
}
// send data to server
void connectServer() {
  int analogOUT = 0;
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    char s[16];
    dtostrf(average, 3, 1, s);
    char sendData[300] = "";
    sprintf(sendData, "GET %s?value=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", PHP_PATH, s, HOST_NAME);
    Serial.println(sendData);
    client.println(sendData);
    Serial.println("********  Closed  **********");
  }
}

参考にした web-site

#47 Power Saving with ESP8266 (Sleep Mode) Tutorial with some Tricks  


ESP8266の真骨頂Deep-Sleepモードの使い方

ESP12E 複数のssidに接続 WiFiMulti

$
0
0

目的: ESP8266 組み立て基板を複数の WiFi のうち最大強度のssidに自動接続したい   ---  WiFiMulti

 例: 自宅でテストした後に、セカンドハウスに取付ける

実験の準備

HiLetGo ESP-12EにマイクロUSBをつないだだけ。

ESP-12Eをserver にして、PCから GET method で信号を、WiFiルーター経由で信号を送り、ESP-12Eに実装されているLEDを点燈する。

イメージ 1

スケッチ

/*
    WiFiMulti_HiLetGo3.ino
    one board computer : HiLetGo
    This sketch trys to Connect to the best AP based on a given list
    reference web-site
    https://qiita.com/rukihena/items/c1b02efcaa37af2f3b32
    ESP8266で複数のSSIDを利用する 
    The first two ssid are always failed
    , probably because two ssid cannot be written on SPIFFS.
    But after three ssid are effective.
*/
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
ESP8266WiFiMulti wifiMulti;
WiFiServer server(80);
wl_status_t prevWifiStatus = WL_IDLE_STATUS;  
void setup() {
  pinMode(16, OUTPUT);
  digitalWrite(16, 0);
 
  Serial.begin(115200);
  delay(10);
 wifiMulti.addAP("D*****G___", "********");
 wifiMulti.addAP("D*****G", "********");
  Serial.println("");
  Serial.println("boot");
  // ここではまだ繋ぎに行かない
}
void loop() {
  wl_status_t wifiStatus = wifiMulti.run();
  if ( prevWifiStatus != wifiStatus ) {
    prevWifiStatus = wifiStatus;
    if( wifiStatus == WL_CONNECTED) {
      Serial.println("WiFi connected");
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      delay(100);
    }
    else {
      // ステータス毎にメッセージ変えたほうがいいかも(各自宿題)
      Serial.println("WiFi error?");
      Serial.println(wifiStatus);
      delay(100);
      return;
    }
  }
  // Start the server
  server.begin();
  // Serial.println("Server started");
  delay(100);
  // Print the IP address
  // Serial.println(WiFi.localIP()); 

// Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wait until the client sends some data
  Serial.println("new client request");
  Serial.println(WiFi.localIP());
  delay(10);
 
  while(!client.available()){
    delay(100);
  }
 
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  delay(100);
  Serial.println(req);
  client.flush();
  delay(10);
  // Match the request
  int val;
  if (req.indexOf("/gpio/0") != -1)
    val = 0;
  else if (req.indexOf("/gpio/1") != -1)
    val = 1;
  else {
    Serial.println("invalid request");
    Serial.println("--------------------");
    client.stop();
    return;
  }
  // Set GPIO16 according to the request.  Red LED
  digitalWrite(16, val);
  client.flush();
  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
  s += (val)?"high":"low";
  s += "</html>\n";
  // Send the response to the client
  client.print(s);
  delay(10);
  Serial.println("Client disconnected");
 
  // The client will actually be disconnected
  // when the function returns and 'client' object is detroyed
  Serial.println("--------------------");
}

結果

下記のように、望んだ動作をしている。

boot
WiFi error?
6
WiFi error?
1
WiFi connected
SSID: D***********G
IP address: 192.168.3.17
new client request
192.168.3.17
GET /gpio/0 HTTP/1.1      <--- LED 点燈
Client disonnected
--------------------
new client request
192.168.3.17
GET /gpio/1 HTTP/1.1      <--- LED 消燈
Client disonnected
--------------------
new client request
192.168.3.17
GET /gpio/8 HTTP/1.1     <--- 無効なGET 情報
invalid request
Client disonnected
--------------------
new client request
192.168.3.17
GET /gpio/4 HTTP/1.1    <--- 無効なGET 情報
invalid request
Client disonnected
--------------------
new client request
192.168.3.17
GET /gpio/0 HTTP/1.1     <--- LED 点燈
Client disonnected
--------------------

考察

今回の実験では、AutoConnectを使わずに複数の ssid につなぐために、あらかじめ複数の ssid をコーディングするという ESP8266WiFiMulti.h を使った。
結果、望んだ動作をして、問題点はなかった。

AutoConnect よりライブラリーのメモリー消費が少ない。さらに、ユーザーは使い方が簡単である。 あらかじめ 接続したい複数の ssid がわかっているなら、AutoConnect よりWiFiMulti が優れている。

さらに、WiFiMultiは、WiFiと切断されても、Loop 内で何度でも自動接続するので信頼性が高い。
一方、AutoConnectはこれができず、一度切断されると、まだ手動でつながなくてはいけない。しかし、誰かがすでに解決しているかもしれない。

有効だったweb site

    https://qiita.com/rukihena/items/c1b02efcaa37af2f3b32
    ESP8266で複数のSSIDを利用する 
    上記のスケッチは、ほぼ丸写しである

別の例

   WiFiMulti    deep-sleep

注意事項1
スケッチをESP-12E に書き込むときに、
消すモード、
スケッチだけ消す、
スケッチと WiFi を消す、
その他
がある。
スケッチだけ消すにすると過去の ssid が残っている。

注意事項2
スケッチを描いた後、deep sleepを有効にするには、D0 とRSTを接続すること。
書き込むときは open 。
イメージ 2



イメージ 3


//
// sensor_to_server12.ino
/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor
  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2650
  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.
  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!
  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  2018/09/25
  Attention :  I2C address in Adafluit Library  --- Adafruit_BME280.h
  changed to     #define BME280_ADDRESS                (0x76)
 ***************************************************************************/
// http://shangtian.hatenablog.com/entry/2017/06/16/223755
// measure and chart update every 1 min
// BME280 test , 2018/9/26,  revised 9/29 for multiple parameter
// Add WiFiMULTI  2018/10/11
#include <ESP8266WiFi.h>
#include  <WiFiClient.h>
#include <ESP8266WiFiMulti.h>   // *****
ESP8266WiFiMulti wifiMulti;  // *****
WiFiServer server(80);   // *****
wl_status_t prevWifiStatus = WL_IDLE_STATUS;   // *****
// WiFiClient instance // *****
WiFiClient client;     // *****
// Time to sleep (in seconds):
const int sleepTimeS = 51;
// host name of server
#define HOST_NAME     "databooster.stars.ne.jp"
// file path of PHP file
#define PHP_PATH      "/shangtianblog12/sensorSet12.php"
// port number
#define PORT_NUMBER   80
float sigma_T = 0;
float average_T = 0;
float sigma_H = 0;
float average_H = 0;
float sigma_P = 0;
float average_P = 0;
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
unsigned long delayTime;
// host name of server
const char* serverURL = "databooster.stars.ne.jp";
// ****************************************************
// ****************************************************
void setup() {
    delay(1000);
    Serial.begin(115200);
    delay(500);
    Serial.println();
    Serial.println(F("BME280 test/1min"));
    bool status;
   
    // default settings
    // (you can also pass in a Wire library object like &Wire2)
    status = bme.begin(); 
    if (!status) {
        Serial.println("Could not find a valid BME280 sensor, check wiring!");
        while (1);
    }
   
    Serial.println("-- Default Test --");
    wifiMulti.addAP("0*****", "*****");   // *****
    wifiMulti.addAP("D*****", "*****);     // *****
   
    Serial.println("");
    Serial.println("boot"); 
    #define MILLISECONDS_TO_WAIT 60000    // 1800000
    unsigned long time_zero = millis();
    time_zero = millis();
    printValues();
    // delay(500);
    // read analog input
    int count = 0;
    int analogOUT_T = 0;
    sigma_T = 0;
    average_T = 0;
    int analogOUT_H = 0;
    sigma_H = 0;
    average_H = 0;
    int analogOUT_P = 0;
    sigma_P = 0;
    average_P = 0;
  while (count < 7) {    //  100
    analogOUT_T = bme.readTemperature() -2.3;
    average_T = average_T + analogOUT_T;
    sigma_T = sigma_T + analogOUT_T * analogOUT_T;
   
    analogOUT_H = bme.readHumidity() + 5;
    average_H = average_H + analogOUT_H;
    sigma_H = sigma_H + analogOUT_H * analogOUT_H;
    analogOUT_P = bme.readPressure() / 100.0F;
    average_P = average_P + analogOUT_P;
    sigma_P = sigma_P + analogOUT_P * analogOUT_P;
    delay(1000);   // 15000
    count++;
  }
 
  average_T = (average_T * 10) / count / 10.0;
  Serial.println ( average_T );
  sigma_T = sqrt( sigma_T / count - average_T * average_T );
  average_H = average_H / count;
  Serial.println ( average_H );
  sigma_H = sqrt( sigma_H / count - average_H * average_H );
  average_P = average_P / count;
  Serial.println ( average_P );
  sigma_P = sqrt( sigma_P / count - average_P * average_P );
// end analog read
// make connection to WiFir
//https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial0wifi.html  ; こじ研
   while (wifiMulti.run() != WL_CONNECTED) {
     Serial.println("Re-connecting...");
     delay(1000);
   }
   wl_status_t wifiStatus = wifiMulti.run();
   Serial.print("wifiStatus: ");
   Serial.println(wifiStatus);
   Serial.print("prevWifiStatus: ");
   Serial.println(prevWifiStatus);
 
   if ( prevWifiStatus != wifiStatus ) {
     prevWifiStatus = wifiStatus;
     if( wifiStatus == WL_CONNECTED) {
       Serial.println("WiFi connected");
       Serial.print("SSID: ");
       Serial.println(WiFi.SSID());
       Serial.print("IP address: ");
       Serial.println(WiFi.localIP());
       delay(100);
     }
     else {
      Serial.println("WiFi error?");
       Serial.println(wifiStatus);
       delay(100);
       return;
     }
   }
 
// Start the server
   server.begin();
   // Serial.println("Server started");
   delay(100);
   // Print the IP address
   // Serial.println(WiFi.localIP()); 
 
// make connection to server
    void connectServer();  // *****
     
  connectServer();
  delay(10);
 
//  if (millis() - time_zero < MILLISECONDS_TO_WAIT) {
//       Serial.println ( MILLISECONDS_TO_WAIT - millis() + time_zero );   
//       delay( MILLISECONDS_TO_WAIT - millis() + time_zero );
//  }
  delay(1000);
  Serial.println("- Sleeping for "+ String(sleepTimeS) +" Seconds");
  Serial.println("- ZZZZZZZZZzzzzzzzzzzz z z z z z\n");
  ESP.deepSleep(sleepTimeS * 1000000);
  delay(1000);
}
void loop() {
// dummy
}
// ***************************************************************
// ***************************************************************
// send data to serverURL
void connectServer() {
  int analogOUT = 0;
  if (client.connect(serverURL, 80)) {    //*******
    Serial.println("connected to serverURL");
    char aveT[16];
    dtostrf(average_T, 3, 1, aveT);
    char aveH[16];
    dtostrf(average_H, 3, 1, aveH);
    char aveP[16];
    dtostrf(average_P, 4, 1, aveP);
    char sendData[300] = "";
    sprintf(sendData, "GET %s?value=%s&value1=%s&value2=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", PHP_PATH, aveT, aveH, aveP, HOST_NAME);
    Serial.println(sendData);
    client.println(sendData);
    Serial.println("********  Closed  **********");
   
  }
}
void printValues() {
    Serial.print("Temperature = ");
    Serial.print(bme.readTemperature() -2.3 );
    Serial.println(" deg");
    Serial.print("Pressure = ");
    Serial.print(bme.readPressure() / 100.0F );
    Serial.println(" hPa");
    // Serial.print("Approx. Altitude = ");
    // Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
    // Serial.println(" m");
    Serial.print("Humidity = ");
    Serial.print(bme.readHumidity() + 5);
    Serial.println(" %");
    Serial.println();
}
//  END


ESP12E ssidを自由に選択

$
0
0

目的

スケッチが完成した後に、WiFiのssidが変わってもアクセスできるようにする。 ライブラリーWiFiManagerを使う。
  例: 親の家に取り付ける。 
     WiFiが不明な人に、ESP12E基板をプレゼントする。

使い方

コーディングのときの設定  --- 重要
イメージ 1

ESP-12Eが、 AutoConnect という名前でWiFiの電波を出しているので、PC(スマホ)からアクセスする。

下図のCongigure WiFi ボタンを押すと、電波を出している WiFiが一覧表示される。
イメージ 2

これらから、目的のWiFiを選び、password を打ち込む。
一度打ち込むと次回から不要。フラッシュメモリーの特殊なアドレスに記録されてるらしい。
普通のSPIFFS領域では無い。

PC(スマホ)がアクセスするWiFi を AutoConnect から、この目的のWiFiに変更する。

スケッチ

/*
 *  WiFiWebServer4.ino
 *  AutoConnect to WiFi by ESP8266WiFiMulti.h
 *  This sketch demonstrates how to set up a simple HTTP-like server.
 *    The server will set a GPIO pin depending on the request
 *    http://server_ip/gpio/0 will set the GPIO low, LED ON
 *    http://server_ip/gpio/1 will set the GPIO high, LED OFF
 *  server_ip is the IP address of the ESP8266 module, will be
 *  printed to Serial when the module is connected.
 *   For example   192.168.3.17
 *  Then Web browser   http://192.168.3.17/gpio/0 or   http://192.168.3.17/gpio/1
 */
#include <ESP8266WiFi.h>
#include <DNSServer.h>    // mandatory,instead, unavaialable for WiFi access after a few good accesses
// #include <ESP8266WebServer.h>   // do not need
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager
// Create an instance of the server
// specify the port to listen on as an argument
  WiFiServer server(80);
void setup() {
  pinMode(16, OUTPUT);
  digitalWrite(16, 0);
  Serial.begin(115200);
  delay(10);
  WiFiManager wifiManager;
  //reset saved settings
  wifiManager.resetSettings();
  wifiManager.autoConnect("AutoConnectAP");
  Serial.println("connected...yeey :)");
  // Print the IP address
  Serial.println(WiFi.localIP());
  delay(3000);
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  // Start the server
  server.begin();
  Serial.println("Server started");
    // Print the IP address
  Serial.println(WiFi.localIP());
}
void loop() {
///  WiFiServer server(80); 
// Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(100);
  }
 
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
 
  // Match the request
  int val;
  if (req.indexOf("/gpio/0") != -1)
    val = 0;
  else if (req.indexOf("/gpio/1") != -1)
    val = 1;
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }
  // Set GPIO16 according to the request.  Red LED
  digitalWrite(16, val);
  client.flush();
  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
  s += (val)?"high":"low";
  s += "</html>\n";
  // Send the response to the client
  client.print(s);
  delay(1);
  Serial.println("Client disonnected");
  // The client will actually be disconnected
  // when the function returns and 'client' object is detroyed
}

考察

コーディングが完成するまでカットアンドトライを繰り返したいへんだった。

この記事で説明したAutoConnectの方式は、ベビーモニターという WiFi カメラと設定手順が同じである。 つまり、システム構成は同じである。 
ベビーモニターは、amazon.com や楽天で簡単に購入でき、100万画素のカメラと回転機構、スピーカー、マイクまで付いているのにたったの5000円ですから、私が作っているIoTシステムはまったく太刀打ち出来ない。
私は、300万画素で10000円のを購入した。サーバーを通してデータ通信をしてるはずだ。だから、すごく応答時間がかかったり、セット回線が切断されてしまう時間帯がある。今後さらにユーザーが増えればさらに悪くなると心配している。 
けっこう便利で、100キロ、300キロ離れたところからスマホでカメラの位置を変えられる。 会話ができる。つまりテレビ電話の機能も付いている。 作るより買って使いこなす人に完璧に負けている。 これを買って分解して何かを組み立てる方が早くて安いと思う。

さらに、さらに、ネットで遠隔制御できるコンセントは1000円で購入できる。しかも温度計も付いている。 会社から帰宅中に電車内で、部屋の温度をスマホ調べ、寒いからエアコンを付けるという、いわゆるホームオートメーションはわずかに1000円でできる時代である。 ESP32でリレーを制御して、レンタルサーバーを借りてシステムを作るよりはるかに安くて信頼できる。 できあいのデバイスを組み合わせてシステムを作るというホビーもアリだ。 海外ではさかんに楽しまれている。昨年、アメリカに出張に行ったとき、ショッピングモール内のホームセンターに、この類のデバイスがたくさん売られていたのを見た。 私の地元のホームセンターにはまだ売ってない。
東急ハンズとか都会に行けば売ってるかも。

ホビーは何を狙って作れば満足感が得られるのかよく考えないといけない。 たいていのIoTシステムはすでに安価に量産されている。 とくに、ホームオートメーション関係のデバイスはすでに安価に売られている。

ESP8266関係のweb siteや e販売店を見ても、ネタはほぼ出尽くしている。

これからの新しい分野は、
・WiFiよりも遠距離で通信可能なLoRa
  これは間違いなく来る。日本が遅れているだけだから。
  LoRaの記事がYoutubeにたくさんあり、面白い。アマチュア無線や、高周波の知識が役立つ。

・量販できないセンサー  ・・・ 放射線、 オゾン、 一酸化炭素、 花粉、 害獣・猫・ねずみ
  ベランダの鳥、 なだれ・洪水、 道路の潅水
  センサーの戦い。 ある程度お金で解決できる。 
  マニアックな世界だがセンサーの種類は多いので、確実に企業と戦える分野である。
  道路の潅水は切実な需要があるね。
  既存のセンサーのカスタマイズでもokだ。
    
・データの利用、ネットワーク
  無数のESP8266がサーバーとしてデータを発信。 
  たとえば、屋久島で、 木ごとのQRコードにかざしたスマホにHTML を発信して、木の種類や樹齢を教える。
  スタンプラリーのスタンプをスマホでゲットする。
  中古車1台づつから流れるHTMLで詳細情報、写真をスマホにゲットする。
  畑の周囲50m毎にESP8266と太陽電池つきモバイルバッテリーを設置し、リレー方式で1km四方の、
  土湿度をPCにデータを送る。
  バッグにQRコードを張っておき、バッグから発信されるクーポン券をスマホでゲットする。

ESP12E, WiFiMulti, deep sleep, BME280, CdS

$
0
0

目的: 今までの要素技術を結合した IoT システムを作る

       複数のssid に自動接続 --- WiFiMulti
               低消費電力   ------ deep sleep
               温度、湿度、大気圧 ---,  BME280, CdS
               照度    --- CdSセル + 10kΩ


イメージ 3

スケッチ

//
// sensor_to_server12E.ino
/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor
  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2650
  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.
  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!
  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  2018/09/25
  Attention :  I2C address in Adafluit Library  --- Adafruit_BME280.h
  changed to     #define BME280_ADDRESS                (0x76)
 ***************************************************************************/
// http://shangtian.hatenablog.com/entry/2017/06/16/223755
// measure and chart update every 1 min
// BME280 test , 2018/9/26,  revised 9/29 for multiple parameter
// Add WiFiMULTI  2018/10/11
// Add CdS   2018/10/17

#include <ESP8266WiFi.h>
#include  <WiFiClient.h>
#include <ESP8266WiFiMulti.h>   // *****
ESP8266WiFiMulti wifiMulti;  // *****
WiFiServer server(80);   // *****
wl_status_t prevWifiStatus = WL_IDLE_STATUS;   // *****
// WiFiClient instance // *****
WiFiClient client;     // *****
// Time to sleep (in seconds):
const int sleepTimeS = 1800;
// host name of server
#define HOST_NAME     "databooster.stars.ne.jp"
// file path of PHP file
#define PHP_PATH      "/shangtianblog12E/sensorSet12.php"
// port number
#define PORT_NUMBER   80
float sigma_T = 0;
float average_T = 0;
float sigma_H = 0;
float average_H = 0;
float sigma_P = 0;
float average_P = 0;
float sigma_L = 0;
float average_L = 0;
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
unsigned long delayTime;
// host name of server
const char* serverURL = "databooster.stars.ne.jp";
// ****************************************************
// ****************************************************
void setup() {
    delay(1000);
    Serial.begin(115200);
    delay(500);
    Serial.println();
    Serial.println(F("BME280 test/1min"));
    bool status;
   
    // default settings
    // (you can also pass in a Wire library object like &Wire2)
    status = bme.begin(); 
    if (!status) {
        Serial.println("Could not find a valid BME280 sensor, check wiring!");
        while (1);
    }
   
    Serial.println("-- Default Test --");
    wifiMulti.addAP("04*****", "*****");   // *****
    wifiMulti.addAP("D8*****", "*****");     // *****
   
    Serial.println("");
    Serial.println("boot"); 
    #define MILLISECONDS_TO_WAIT 60000    // 1800000
    unsigned long time_zero = millis();
    time_zero = millis();
    printValues();
    // delay(500);
    // read analog input
    int count = 0;
    float analogOUT_T = 0;
    sigma_T = 0;
    average_T = 0;
    float analogOUT_H = 0;
    sigma_H = 0;
    average_H = 0;
    float analogOUT_P = 0;
    sigma_P = 0;
    average_P = 0;
    float analogOUT_L = 0;
    sigma_L = 0;
    average_L = 0;
  while (count < 7) {    //  100
    analogOUT_T = bme.readTemperature() -2.3;
    average_T = average_T + analogOUT_T;
    sigma_T = sigma_T + analogOUT_T * analogOUT_T;
   
    analogOUT_H = bme.readHumidity() + 5;
    average_H = average_H + analogOUT_H;
    sigma_H = sigma_H + analogOUT_H * analogOUT_H;
    analogOUT_P = bme.readPressure() / 100.0F;
    average_P = average_P + analogOUT_P;
    sigma_P = sigma_P + analogOUT_P * analogOUT_P;
    analogOUT_L = analogRead(A0);
    average_L = average_L + analogOUT_L;
    sigma_L = sigma_L + analogOUT_L * analogOUT_L;
    delay(1000);   // 15000
    count++;
  }
 
  average_T = (average_T * 10) / count / 10.0;
  Serial.println ( average_T );
  sigma_T = sqrt( sigma_T / count - average_T * average_T );
  average_H = average_H / count;
  Serial.println ( average_H );
  sigma_H = sqrt( sigma_H / count - average_H * average_H );
  average_P = average_P / count;
  Serial.println ( average_P );
  sigma_P = sqrt( sigma_P / count - average_P * average_P );
  average_L = average_L / count;
  Serial.println ( average_L );
  sigma_L = sqrt( sigma_L / count - average_L * average_L );
// end analog read
// make connection to WiFir
//https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial0wifi.html  ; こじ研
   while (wifiMulti.run() != WL_CONNECTED) {
     Serial.println("Re-connecting...");
     delay(1000);
   }
   wl_status_t wifiStatus = wifiMulti.run();
   Serial.print("wifiStatus: ");
   Serial.println(wifiStatus);
   Serial.print("prevWifiStatus: ");
   Serial.println(prevWifiStatus);
 
   if ( prevWifiStatus != wifiStatus ) {
     prevWifiStatus = wifiStatus;
     if( wifiStatus == WL_CONNECTED) {
       Serial.println("WiFi connected");
       Serial.print("SSID: ");
       Serial.println(WiFi.SSID());
       Serial.print("IP address: ");
       Serial.println(WiFi.localIP());
       delay(100);
     }
     else {
      Serial.println("WiFi error?");
       Serial.println(wifiStatus);
       delay(100);
       return;
     }
   }
 
// Start the server
   server.begin();
   // Serial.println("Server started");
   delay(100);
   // Print the IP address
   // Serial.println(WiFi.localIP()); 
 
// make connection to server
    void connectServer();  // *****
     
  connectServer();
  delay(10);
 
//  if (millis() - time_zero < MILLISECONDS_TO_WAIT) {
//       Serial.println ( MILLISECONDS_TO_WAIT - millis() + time_zero );   
//       delay( MILLISECONDS_TO_WAIT - millis() + time_zero );
//  }
  delay(1000);
  Serial.println("- Sleeping for "+ String(sleepTimeS) +" Seconds");
  Serial.println("- ZZZZZZZZZzzzzzzzzzzz z z z z z\n");
  ESP.deepSleep(sleepTimeS * 1000000);
  delay(1000);
}
void loop() {
// dummy
}
// ***************************************************************
// ***************************************************************
// send data to serverURL
void connectServer() {
  int analogOUT = 0;
  if (client.connect(serverURL, 80)) {    //*******
    Serial.println("connected to serverURL");
    char aveT[16];
    dtostrf(average_T, 3, 1, aveT);
    char aveH[16];
    dtostrf(average_H, 3, 1, aveH);
    char aveP[16];
    dtostrf(average_P, 4, 1, aveP);
    char aveL[16];
    dtostrf(average_L, 4, 1, aveL);
    char sendData[300] = "";
    sprintf(sendData, "GET %s?value=%s&value1=%s&value2=%s&value3=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", PHP_PATH, aveT, aveH, aveP, aveL,    HOST_NAME);
    Serial.println(sendData);
    client.println(sendData);
    Serial.println("********  Closed  **********");
   
  }
}
void printValues() {
    Serial.print("Temperature = ");
    Serial.print(bme.readTemperature() -2.3 );
    Serial.println(" deg");
    Serial.print("Humidity = ");
    Serial.print(bme.readHumidity() + 5);
    Serial.println(" %");
    Serial.print("Pressure = ");
    Serial.print(bme.readPressure() / 100.0F );
    Serial.println(" hPa");
    Serial.print("Brightness = ");
    Serial.print(analogRead(A0));
    Serial.println(" -");
    // Serial.print("Approx. Altitude = ");
    // Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
    // Serial.println(" m");
  
    Serial.println();
}
//  END

ESP12E, HTTP AP 実験1

$
0
0

目的  ---   AP機能の検証

ESP-12Eを webserverのアクセスポイントとして動作させる実験をする
つまり、WiFiルーターを使わない。 レンタルサーバーも使わない。

ESP-12EとPCだけで、WiFiをとおしてデータ通信する。
ESP-12Eとスマホだけで、WiFiをとおしてデータ通信する。

参考文献

nodemcu esp8266 wifi access point

実験

ここの記事に紹介されスケッチをHiLetGo ESP-12E用に修正し、動作を確認した。

   http://okiraku-camera.tokyo/blog/?p=3426
      ESP-WROOM-02のWEBサーバーでLEDをチカチカさせてみる

結果

 動作した。
 問題点:最初に http://192.168.4. にアクセスしてもダメであり、 http://192.168.4.1/cmd?LED=off ならok。


ツール 設定値
イメージ 1

スケッチ、 書き込み終了
イメージ 2


書き込んだESP-12E、 何も接続してない
イメージ 3

ssidは私が自由に決められる
IP アドレスは常に 192.168.4.1
イメージ 4


PCまたはスマホの WiFiの画面を開き
ESP8266AP-192-168-4-1 を探す。もし無かったら失敗です
これを有効にする
イメージ 5

IE でもChrome でもアクセスできた
イメージ 6

on ボタンを押すと、設計どおり Red LED が点燈
イメージ 7

OFFで消灯
イメージ 8


このように、設計通りの動作をした。
こんな小さいのに、 アクセスポイント と WiFiの両方の機能を持っているのはグレート。

ubuntuでも使えた。 当たり前。
イメージ 9


Ipad mini ではURLを打ち込めない。実験向きではない。

スケッチ

// webserver_AP_LED.ino
// original sketch is written in 
//    http://okiraku-camera.tokyo/blog/?p=3426
//    ESP-WROOM-02のWEBサーバーでLEDをチカチカさせてみる
// arranged for HiLetGo ESP-12E
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Ticker.h>
#define RED_LED 16
#define GRN_LED 2
Ticker ticker;
const char* ssid = "ESP8266AP-192-168-4-1";
const char* password = "password";
ESP8266WebServer server(80);
enum  led_style {led_off = 1, led_on = 0, slow_blink = 2, fast_blink = 3 } ;
static enum led_style red_led = led_off;
long tick_counter = 0;
void ticker_func() {
  static byte led_state = 0;
  tick_counter++;
  if (red_led == led_off)
    led_state = 1;
  else if  (red_led == led_on)
    led_state = 0;
  else if ((red_led == slow_blink && (tick_counter % 100 == 0)) ||
           (red_led == fast_blink && (tick_counter % 40 == 0)))
    led_state ^= 1;
  digitalWrite(RED_LED, led_state);
}
static const char* cpResponse400 = "<HTML><BODY>Bad request</BODY></HTML>\r\n";
static const char* cpResponse200 = "<HTML><BODY style='font-size:30px;'>HiLetGo ESP-12E HTTP Access Point to LED control<br/><br/>"
                                   "<br/><a href=/cmd?LED=on>on</a><br/><a href=/cmd?LED=off>off</a><br/>"
                                   "<a href=/cmd?LED=blink1>blink1</a><br/><a href=/cmd?LED=blink2>blink2</a><br/>"
                                   "</BODY></HTML>\r\n";
void send_bad_request() {
  server.send(400, "text/html", cpResponse400);
  Serial.println("Bad request");
}
// /cmd?LED=on/off/blink1/blink2
void handleCommand() {
  if (!server.hasArg("LED")) {
    send_bad_request();
    return;
  }
  String cmd = server.arg("LED");
  Serial.println("handleCommand() LED=" + cmd);
  if (cmd == "on")
    red_led = led_on;
  else if (cmd == "off")
    red_led = led_off;
  else if (cmd == "blink1")
    red_led = slow_blink;
  else if (cmd == "blink2")
    red_led = fast_blink;
  server.send(200, "text/html", cpResponse200);
}
void setup() {
  Serial.begin(115200);
  pinMode(RED_LED, OUTPUT);
  pinMode(GRN_LED, OUTPUT);
  digitalWrite(RED_LED, 1);
  digitalWrite(GRN_LED, 1);
  ticker.attach_ms(10, ticker_func);
  WiFi.softAP(ssid, password);
  IPAddress ip = WiFi.softAPIP();
  Serial.println("");
  Serial.println(ssid + String(" starts.."));
  Serial.print("this AP : ");
  Serial.println(ip);
  server.on("/cmd", handleCommand);
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
  delay(1);
}






ESP12E, HTTP AP 実験2

$
0
0

目的  ---   AP機能の検証

ESP-12Eを webserverのアクセスポイントとして動作させる実験をする
つまり、WiFiルターを使わない。 レンタルサーバーも使わない。

ESP-12EとPCだけで、WiFiをとおしてデータ通信する。
ESP-12Eとスマホだけで、WiFiをとおしてデータ通信する。

実験

Arduino に付属しているスケッチサンプルの一つであるWiFiAccessPoint.inoを動かす

結果

 動作した。
 http://192.168.4.1 にアクセスするとすぐにPCに表示される。

ツール 設定値


書き込んだESP-12E、 何も接続する必要なし

ssidは私が自由に決められる
IP アドレスは常に 192.168.4.1
イメージ 1

Double bite charactors are garbled.
This is caused by coding   , "text/html", "<h1>朝倉さや</h1>");
,and this is a small issue.
イメージ 2

スケッチ

/*
   Copyright (c) 2015, Majenko Technologies
   All rights reserved.
   Redistribution and use in source and binary forms, with or without modification,
   are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright notice, this
     list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice, this
     list of conditions and the following disclaimer in the documentation and/or
     other materials provided with the distribution.
 * * Neither the name of Majenko Technologies nor the names of its
     contributors may be used to endorse or promote products derived from
     this software without specific prior written permission.
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Create a WiFi access point and provide a web server on it. */
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

/* Set these to your desired credentials. */
const char *ssid = "asakurasaya";
const char *password = "asakurasaya";

ESP8266WebServer server(80);

/* Just a little test message.  Go to http://192.168.4.1 in a web browser
   connected to this access point to see it.
*/
void handleRoot() {
  server.send(200, "text/html", "<h1>朝倉さや</h1>");
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Configuring access point...");

  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  server.on("/", handleRoot);
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
}



別の似たような スケッチ

// udemmy_WiFiAccessPoint.ino
// WiFi Simple Access Point Server
// Written by: Thomas Tongue
// Date: July 25th, 2015
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

const char* ssid     = "asakura_saya";
const char* password = "asakura_saya";

ESP8266WebServer server(80);

const int LED=2;

void handleRoot() {
  server.send(200, "text/html", "<h1>Hello from your ESP8266!</h1>");
}

void handleNotFound(){
  digitalWrite(LED, 1);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  digitalWrite(LED, 0);
}

void setup() {
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
  Serial.begin(115200);
  delay(10);
  // We start by connecting to a WiFi network
 
  Serial.print("Configuring Access Point ");
  Serial.println(String(ssid));

  WiFi.softAP(ssid, password);
  delay(5000);
  Serial.println("Done.");
  IPAddress myIP = WiFi.softAPIP();
  Serial.println("My Access Point IP address: ");
  Serial.println(myIP); 

  server.on("/", handleRoot);
 
  server.onNotFound(handleNotFound);
 
  server.begin();
 
  Serial.println("HTTP server started");
  Serial.flush();
}

void loop() {
  server.handleClient();
}


ESP12E, server Access Point 実験3

$
0
0

目的  ---   AP機能の検証

ESP-12Eを webserverのアクセスポイントとして動作させる実験をする
つまり、WiFiルターを使わない。 レンタルサーバーも使わない。

ESP-12EとPCだけで、WiFiをとおしてデータ通信する。
ESP-12Eとスマホだけで、WiFiをとおしてデータ通信する。

実験

下記のデモを、HiLetGo ESP-12Eに合うように修正し動作を確認する。

ESP8266 example: Wi-Fi Access point, static IP, web-server and remote GPIO control
By Stan  | May 2, 2017

結果

数十回の修正の後、http://42.42.42.42/ にアクセスすると希望どうりに動作した。 この IP はスケッチの中で自由に変えられる。


ツール 設定値
蛇足ですが、Generic ESP8266の設定でも書き込めた



イメージ 3


ESP-12Eの配線
可変抵抗の中間端子をA0に接続、他を3.3V  GND に接続した。
CdSが受ける照度を変えながら最適な直列抵抗値を探した。
結果、暗いほうの感度がほしいので10kΩにした。
明るいほうでアナログ出力が飽和しないためには、5k, 1k と下げれば良い。
結果
Turn it ONを押すとLEDがすぐに点灯した
Uptime とBrightnessは1秒ごとに更新されるようにスケッチを修正した
修正前 <meta http-equiv='refresh' content='10'/>\
修正後 <meta http-equiv='refresh' content='1'/>\

このスケッチは今後応用できそうである
イメージ 1

イメージ 2

感想

オリジナルのスケッチを修正するために、HTMLの知識が必要だった。なんとなくわかる。
昔はバリバリでHTMLを書いていたが退化してしまった。また勉強しないとなあ。
IoTを楽しむには下記の幅広い知識が必要になると改めて感じた。
IoTは通常の電子技術者にとってすらハードルが高いと思う。
ソフトしかいじってない人には、アナログ回路は難しいと思う。自分で回路を組むのがいい。
なので、マスターすれば食っていける。

デジタル回路の初歩
アナログ回路の初歩
Arduino ,  ESP8266のセットアップ
C++
PHP
HTML
Javascript

スケッチ

オリジナルのスケッチを HiLetGo RSP-12E に利用できるように、下記のスケッチは細かい修正がされている。

// https://42bots.com/tutorials/esp8266-example-wi-fi-access-point-web-server-static-ip-remote-control/
// ESP8266 example: Wi-Fi Access point, static IP, web-server and remote GPIO control
// Create a WiFi access point and provide a web server on it.
// For more details see
http://42bots.com.
// arranged for HiLetGo ESP-12E

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

IPAddress apIP(42, 42, 42, 42);  // Defining a static IP address: local & gateway
                                        // Default IP in AP mode is 192.168.4.1

/* This are the WiFi access point settings. Update them to your likin */
const char *ssid = "asakurasaya1";
const char *password = "asakurasaya1";

// Define a web server at port 80 for HTTP
ESP8266WebServer server(80);

const int ledPin = 16; // 16 built in red ,  2  built in blue
bool ledState = false;

void handleRoot() {
  digitalWrite (ledPin, server.arg("led").toInt());
  ledState = digitalRead(ledPin);
 /* Dynamically generate the LED toggle link, based on its current state (on or off)*/
  char ledText[80];
 
  if (ledState) {
    strcpy(ledText, "LED is OFF. <a href=\"/?led=0\">Turn it ON!</a>");
  }
  else {
    strcpy(ledText, "LED is ON. <a href=\"/?led=1\">Turn it OFF!</a>");
  }
 
  ledState = digitalRead(ledPin);

  char html[1000];

  int sec = millis() / 1000;
  int min = sec / 60;
  int hr = min / 60;

  int brightness = analogRead(A0);
  brightness = (int)(brightness + 5) / 10; //converting the 0-1024 value to a (approximately) percentage value

// Build an HTML page to display on the web-server root address
  snprintf ( html, 1000,
"<html>\
  <head>\
    <meta http-equiv='refresh' content='10'/>\
    <title>ESP8266 WiFi Network</title>\
    <style>\
      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; font-size: 1.5em; Color: #000000; }\
      h1 { Color: #00AA00; }\
    </style>\
  </head>\
  <body>\
    <h3>ESP8266 Wi-Fi Access Point and Web Server Demo</h3>\
    <p>Uptime: %02d:%02d:%02d</p>\
    <p>Brightness: %d%</p>\
    <p>%s<p>\
  </body>\
</html>",
    hr, min % 60, sec % 60,
    brightness,
    ledText
  );
//     <p>Uptime and brightness refresh every 10 seconds. Click <a href=\"javascript:window.location.reload();\">here</a> to refresh the page now.</p>\




  server.send ( 200, "text/html", html );
  // digitalWrite ( ledPin, 1 );
}




void handleNotFound() {
  digitalWrite ( ledPin, 0 );
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";


  for ( uint8_t i = 0; i < server.args(); i++ ) {
    message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
  }


  server.send ( 404, "text/plain", message );
  digitalWrite ( ledPin, 1 ); //turn the built in LED on pin DO of NodeMCU off
}




void setup() {
  pinMode ( ledPin, OUTPUT );
  digitalWrite ( ledPin, 0 );
 
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  Serial.println("Configuring access point...");


  //set-up the custom IP address
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));   // subnet FF FF FF 00 
 
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);


  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
 
  server.on ( "/", handleRoot );
  server.on ( "/led=1", handleRoot);
  server.on ( "/led=0", handleRoot);
  server.on ( "/inline", []() {
    server.send ( 200, "text/plain", "this works as well" );
  } );


  server.onNotFound ( handleNotFound );
 
  server.begin();
  Serial.println("HTTP server started");
}




void loop() {
  server.handleClient();
}



ESP-12E 環境センサーの実地試験

$
0
0


実地試験に使ったESP-12E デバイス


イメージ 1


ACアダプターから5Vを作り、ESP-12Eへ供給した。
ケースに入れず、基板を裸で、コンセントにぶら下げた。
いずれは、ケースに入れ、単三乾電池で動作させるつもりである。

リビング
イメージ 3

キッチン、冷蔵庫の横
イメージ 4

結果

問題なくすぐに動作を開始した。ブラウザーでこのグラフを難なく見れた。

イメージ 2

評価内容


1km以上離れた別の家のコンセントに差し込んだ。
この家の ssid とpassword はあらかじめ調べておき、 WiFiMulti用にスケッチに書き込んでおいた

評価項目と結果


WiFiMulti  --- 正常に機能した

各センサー  --- 正常に機能した
 しかし、BME280 に組み込まれている温度、湿度、気圧は少し違ってる気がする。
 あらかじめBME280に書き込まれている補正データを使って補正したほうがいいかも。
 CdSも個体差がある。この補正はCdSの直列抵抗値を変えればいいのかも。ソフトでも補正できるけれど。

deep sleep
 何の問題もなく動作した

ESP12E, HTTP AP 実験4

$
0
0

目的

"ESP12E, http AP 実験1"の改良であり、HTML を ファイル index.html に記述し、SPIFFS に書き込む。
つまり、
これに、built-in LEDを点燈する機能を追加しただけである。

実験1と同じく、ESP-12Eをアクセスポイントとして動作させる構成である。
したがって、ルーターとレンタルサーバーはいらない。
ESP-12E と PC またはスマホだけで遊べる。
ESP-12Eへのアクセスは、  hppt://192.168.4.1

結果

sketch を改良するために予想外に時間がかかってしまったが、その分、C++ のコードの勉強になった。
結果、下図のように希望どうりの動作をした。

イメージ 3


イメージ 1

イメージ 2


sketch

// index.html in spiffs  --> WiFi as HTML server Access Point --> Client web browser 
//
// SPIFFS_SERVER5.ino
//
// Original sketch is written in 
//    https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial5.html
//    ������  �t�@�C���V�X�e���̎g�����i�P�j:�@�A�b�v���[�_���g��
//    arranged for HiLetGo ESP-12E
//
// Reference sketches are below 2
//    http://okiraku-camera.tokyo/blog/?p=3426
//    ESP-WROOM-02��WEB�T�[�o�[��LED���`�J�`�J�����Ă݂�
//
//    https://dbpro.xyz/5055
//    ESP8266(ESP-WROOM-02) web�T�[�o�[
//
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <FS.h>
// SPIFFS_SERVER5.ino
#define RED_LED 16
#define BLUE_LED 2
#define LED_ON 0
#define LED_OFF 1
const char *ssid = "asakurasaya2";
const char *pass = "asakurasaya2";
ESP8266WebServer Server(80);
// handle on
// SPIFFS_SERVER5.ino
String html = "/index.html";
void onDev1() {
  Serial.println("device1_ON");
  digitalWrite(BLUE_LED,LED_ON);
  Server.send(200, "text/html", html);
}
void offDev1() {
  Serial.println("device1_OFF");
  digitalWrite(BLUE_LED,LED_OFF);
  Server.send(200, "text/html", html);
}
void onDev2() {
  Serial.println("device2_ON");
  digitalWrite(RED_LED,LED_ON);
  Server.send(200, "text/html", html);
}
void offDev2() {
  Serial.println("device2_OFF");
  digitalWrite(RED_LED,LED_OFF);
  Server.send(200, "text/html", html);
}
//

void handleNotFound() {
  if (! handleFileRead(Server.uri())) {
    Serial.println("404 not found");
    Server.send(404, "text/plain", "File not found in ESP-12E");
  }
}
//  MIME
String getContentType(String filename){
  if(filename.endsWith(".html") || filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else return "text/plain";
}
// SPIFSS
bool handleFileRead(String path) {
  Serial.println("handleFileRead: trying to read " + path);
  if (path.endsWith("/")) path += "index.html";
  String contentType = getContentType(path);
  if (SPIFFS.exists(path)) {
    Serial.println("handleFileRead: sending " + path);
    File file = SPIFFS.open(path, "r");
    Server.streamFile(file, contentType);
    file.close();
    Serial.println("handleFileRead: sent " + path);
    return true;
  }
  else {
    Serial.println("handleFileRead: 404 not found");
    Server.send (404, "text/plain", "ESP: 404 not found");
    return false;
  }
}
void setup() {
  pinMode(BLUE_LED, OUTPUT);  // blue led
  pinMode(RED_LED, OUTPUT);   // red led
 
  digitalWrite(BLUE_LED,LED_OFF);
  digitalWrite(RED_LED,LED_OFF);
 
  SPIFFS.begin();
  Serial.begin(115200);
  delay(100);
  Serial.println("\n*** Dongbeino ***");
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, pass);
  Serial.print("network: "); Serial.println(ssid);
  Serial.print("address: "); Serial.println(WiFi.softAPIP());

  // handle server
  Server.on ("/on1/", onDev1); // SPIFFS_SERVER5.ino
  Server.on ("/off1/", offDev1); // SPIFFS_SERVER5.ino
  Server.on ("/on2/", onDev2); // SPIFFS_SERVER5.ino
  Server.on ("/off2/", offDev2); // SPIFFS_SERVER5.ino
  Server.onNotFound(handleNotFound);
  Server.begin();
}
void loop() {
  Server.handleClient();
  delay (10);
}

index.html

<!-- dummy -->
<!-- dummy -->
<!-- dummy -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ESP-12E</title>
<h1>Hello ESP8266</h1>
<span id="view_clock"></span>
<br><br>
<style>
h1 {color:#ffeeaa;}
h3 {color:#fff;}
body{
  font-size:14px;
  text-align:center;
  color:#fff;
  margin:0px;
  padding:0px;
  background-color:#333;
}
button{
  font-size:20px;
  width:48%;
  height:80px;
  background-color:#ccc;
}
button:hover{
  opacity: 0.8;
  cursor: pointer;
}
a {text-decoration:underline}
a {color:#ddd}
</style>
</head>
<body>
<button id="on1" onClick=sendOn1()>Blue LED ON</button>
<button id="off1" onClick=sendOff1()>Blue OFF</button>
<br>
<button id="on2" onClick=sendOn2()>Red LED ON</button>
<button id="off2" onClick=sendOff2()>Red LED OFF</button>
<br>
<p><img src="/esp8266ON.jpg"></p>
<p><a href="/diy.jpg">ESP-12E</a></p>

<script type="text/javascript">
window.onload = function() {
 send("/status/");
 
}
function sendOn1() {
  var d1 = document.getElementById("on1");
  d1.style.backgroundColor = "#BCA9F5";
  send("/on1/");
}
function sendOff1(){
  var d1 = document.getElementById("on1");
  d1.style.backgroundColor = "#ccc";
  send("/off1/");
 
}
function sendOn2(){
  var d2 = document.getElementById("on2");
  d2.style.backgroundColor = "#F6D8CE";
  send("/on2/");
}
function sendOff2(){ 
  var d2 = document.getElementById("on2");
  d2.style.backgroundColor = "#ccc";
  send("/off2/");
}
function send(url){
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.send();
}
<!-- // view_clock
timerID = setInterval('clock()',500); // 500ms
function clock() {
  document.getElementById("view_clock").innerHTML = getNow();
}
function getNow() {
  var now  = new Date();
  var year = now.getFullYear();
  var mon  = ("0"+(now.getMonth()+1)).slice(-2); // +1
  var day  = ("0"+now.getDate()).slice(-2);
  var hour = ("0"+now.getHours()).slice(-2);
  var min  = ("0"+now.getMinutes()).slice(-2);
  var sec  = ("0"+now.getSeconds()).slice(-2);
  var s = year + "-" + mon + "-" + day + " " + hour + ":" + min + ":" + sec + "";
  return s;
}
//-->
</script>
</body>
</html>

参考文献

ESP-12E 環境センサ,電池駆動

$
0
0

目的

ESP-12Eを利用した環境センサーで外気温を測定する。
センサーは今まで開発した回路をそのまま使う。

アルカリ電池

micro USB充電、1.5Vリチウム乾電池

モバイルバッテリー cheero CANVAS

 温度,湿度,気圧,照度
 セカンドハウス  ベランダ

構造

・ESP-12Eへの電源入力は、5V と3.3V の2種類がある。
 5V端子へ電池を接続すれば、ESP-12Eに組み込まれている安定化電源ICで3.3Vに安定化されるので、
 センサの測定精度に不安が無い。
 逆に、3.3Vに電池を直接接続すると、電池の消耗に伴い電圧は低下してしまう。
 この結果、センサーの測定精度に不安があるし、何ボルトまで低下しても動作し続けるのかスリルがある。

・電池の種類
 100均で、5本で100円で買える単三電池は安価である。もっともエコである。
 充電可能な電池は一見エコだが、初期投資が高いのでトータルで高価であり、また充電器を生産するのに
 多量のエネルギーを消費するので決してエコではない。

・単三電池を直列接続し、3.3V端子に直接つないだnet記事がいくつかあり、2Vまで低下しても動作してるので
 けっこういけそう。 これが一番単純な構成なので実験が簡単。まず最初にこれで実験することにした。
 いろいろ計算しているsiteがあるが、私の実験では計算どおりにならないはずである、
 なぜなら、我が地域は冬季にマイナス5から10度に低下するので、電池の性能が低下するからである。

・アルカリ電池は低温では性能が大きく低下するらしい。
 一方、リチウム電池はマイナス40度まで動作するらしい。
 なので、今回はアルカリ電池を使うが、追加でリチウム電池での実験もする。

実験1

単三アルカリ電池2本を、3.3V端子に接続した。 100均で、5本で100円の安物である。
初期電圧は、3.2Vだった。正常である。
イメージ 1

電源スイッチが付いてるので使いやすい
イメージ 2

3.3V端子に半田付け
これくらいの配線はすでに小学生のときにやってました。
イメージ 3

3.3V端子に、470uFの電解コンが接続されている。 電池の内部抵抗が高くなってもWiFiを動作できるように。
イメージ 4

ラフにアセンブリ。
イメージ 5

タッパに入れる
イメージ 6

ベランダに置く。WiFiの電波がルーターに届き、データがサーバーにsaveされてるのを確認した。
イメージ 7

ベランダはマンションの4階。 場所は寒冷地。 山形県米沢市 上杉神社から徒歩5分の町の中心部である。
冬の深夜はたいていマイナス5度以下。マイナス10度以下も。
毎日深夜4時になると、行政から委託された土木業が雪かきをする。
そういうとてもとても寒い地域である。
このために、低温テストにはもってこいのチャンス到来である。

風が吹くと雪がベランダの奥まで吹き込むので、50cm, 100cm の台を用意してこの上に置かないと雪にうずもれるはずである。 物干しに吊るすのがいいかも。
イメージ 8


実験1の結果

12;28にブルーの線で示した気温が54度にも達した。 タッパに密封したために発生した温室効果である。
これは本当の気温ではない。

イメージ 9


実験2


対策:密閉しない容器に入れる。 ドラッグストアで、冷蔵庫内を整理する容器を138円で購入した。
横が網になっているために、空気がとても通りやすい。
この中に ESP-12Eユニットを入れる。

イメージ 10

イメージ 11


実験2 結果


小雨だったので、昨日の不具合が解決されたか検証できなかった。
よって、明日以降も継続する。

しかし、湿度がすごく上がっているので、湿度計は健全なのだとわかった。

また、小雨で薄暗かったにもかかわらず、赤線で示した照度がサチッてる。
直列接続した10kオームを小さくすれば解決できるが消費電流が大きくなってしまうので、できない。
解決策として、変数変換という手段がある。ロジット変換でいけるかも。これは、one-sided distributionを正規分布に変換できるすごいやつだ。

イメージ 12

変動が大きいので、見ていて楽しい。
測定された気温は、気象庁の気温よりやはり高い原因は、直射日光が当たるからである。
ちなみに、百葉箱がamazonで売られているが、10万円以上もする。高すぎて買えない。
将来、暇になったら自作しよう。
なので、今回はこれで完成したことにしちゃう。
イメージ 16

実験3 モバイル リチウムバッテリー

私の住んでいる寒冷地でも動作できるであろうリチウムバッテリーで実験をしよう。
ほとんどのモバイルバッテリーは消費電流が小さくなると出力をシャットダウンしてしまうので、deep sleep で動作するESP-12Eでは働かない。
しかし、こんなIoT機器用に設計されたモバイルバッテリーが売られている。
cheero CANVAS である。 電気量から見ると割り高だが、amazon.com ではこれしか見つからなかったので仕方が無い。
この実験も並行して実施する。

イメージ 13

しかし問題が。
電気出力のときは常にLEDが点燈しているため、
半年も電池が持つはずが無い。外れでした。決してIoT用のモバイルバッテリーではない。
でも、買ってしまったし、充電が終わったので、しかたなく実験開始。
イメージ 14

右側のやつ。
cheero CANVAS とは輪ゴムでアセンブリし、ベランダに置く。
イメージ 15

実験3 結果 モバイル リチウムバッテリー

cheero CANVAS でちゃんと動作したのを確認した。
でも、cheero CANVASは LED が付きっぱなしなので、バッテリーの寿命は1週間以下だろう。

そこで、次の実験のためにLED の点燈しないリチウムバッテリーを購入中である。高価であった。
私のセカンドハウスがある寒冷地ではマイナス5や10度まで気温が低下するので、リチウムバッテリーがいいみたいである。アルカリ電池は無理との記事を読んだことがある。 実に価格差が10倍もある。
したがって、寒冷地においては、IoTシステムの部品の中で、バッテリーが一番高価になるかもなあ。

しかし、http://eleclabyrinth.blog.fc2.com/blog-entry-149.html によれば、アルカリ電池でもマイナス10度で動作するという Panasonic のデータが載っている。 電気容量は40%に低下する。 怖がることは無い、並列にでかいコンデンサーを半田付けすればいいだろう。
私が100均で購入している5本で100円のやつはPanasonicじゃないから、もっと悪いかもなあ。凍結しちゃうかも。

ということで、これから厳冬の季節に突入するが、電池の低温性能の試験にはもってこいのチャンスである。
これから、アウトドアにおけるIoTシステムの耐寒テストを開始する。

1.5Vリチウム乾電池はアルカリ乾電池よりもずっといい。 たとえば、消耗しても電圧が一定、電圧がやや高く好都合。 大容量。 耐寒性あり。 

電圧が3VというCR2032もいいかもと思っている。 CR2032は40個で1300円である。しかし、内部抵抗がすごく高いので、500から1000円もするスーパーキャパシタや電気二重層と併用するとか、または10個並列して内部抵抗を1/10にするとか、対策が考えられる。

こうやって比較すると、1.5Vリチウム乾電池がいいのかなあと思う。 価格は量販店で、1本150円である。 2本で300円で、1年もてば立派である。

イメージ 17


実験4 充電式リチウムイオン充電池

充電できる単三乾電池型、1.5Vリチウムバッテリーが5種類以上から売られている。micro USBケーブルやUSB に差し込んで充電する。したがって、充電は5Vである。
1本600円から1000円と高価であるが、大人なのでまったく問題ない。

amazonの評価を読むと、粗悪品があるようなので、amazonの評価をよく読んだほうがいい。 安いのはダメだ。
なので、一番高価な製品を購入した。 大人なのでまったく問題ない。

出力は、DDコンで安定化された1.5Vである。
中身は、3V以上のリチウム・ポリマー・バッテリーが入っていて、DC-DCコンバータで1.5Vに降圧して出力している。
ラジオを近づけるとノイズが乗るという不満や、PCのコントローラがまったく動かないという不満がnetで発見されたので、DC-DCコンバータが働いているのは間違いない。つまり、DDコンは発振しているので、これから出る異常な電波が、ラジオのノイズになり、またPCと交信するデバイスを動かなくしてしまう。

ずっとDDコンが働いているのか、外部抵抗が低いときだけ働くのか不明であり、不安である。
なので、この疑問を検証してみる。
ESP-12Eユニットの番号は B である。
2本直列を、3.3V端子に半田付けした。

結果的に、3個のESP-12E ユニットを並行して実験中である。

イメージ 18

仕様:
標準電圧:1.5V
大容量:1500mAh
定格エネルギー:2.25wh
出力電圧:1.5V
入力電圧:5V
♠充電電圧制限:5V
フル充電時間:約1時間
材質:高品質の耐火PC +ステンレス鋼
★電池寿命:リサイクル利用で1000回まで

イメージ 19


左から、A: 1.5V x 2 本アルカリ、 B: 1.5V x 2本 充電式リチウム乾電池、 E: 5V IoT用モバイルバッテリー 
イメージ 20


実験4 充電式リチウムイオン充電池 結果  2018/11/10 8:00

結果:
2018/11/10 8:00
3種類の電池で動作するESP-12E ユニットは正しくデータを計測している。

充電式リチウム乾電池は、DDコンから出る高周波ノイズが心配であったが、無事に成功した。使える、ラッキー。  この乾電池は、出力が1.5Vに安定化されているので、センサーの精度に不安がないという点がメリットである。 がんばって欲しい。 3V分、2本で1,900円と高価であるが、大人なのでまったく問題ない。

また、別の実験をした。
 Twharf製の充電式リチウムイオン充電池を髭剃りに装着しON。 さらに、ラジオに接触させたが、ラジオの音はまったくノイズが増えてない。 すばらしい。
 よって、Twharf製の充電式リチウムイオン充電池からはじゃまな電波は漏洩してない。理由は設計が優秀だからであろう。 ハウジングがステンレスであり導体なので、電波は漏洩しないのだろう。

たとえばニッケル水素を買って、充電器を買うよりも安価だし、夏場でも自己放電は無いし、出力電圧は安定してるし、 総合的に考えるとすばらしいと思う。
量産効果で、1本500円、300円まで安くなれば、乾電池界でメジャーになるだろう。

このまま、モニターを継続する。

本当は、5本で100均のアルカリ単三電池が使えればもっとラッキーです。


アルカリ電池
イメージ 23


実験5 結果 2018/11/11 8:00


3個とも正常である。

測定ばらつきに関して
測定値のチャートが上下に変動してるのを滑らかにするには、測定間隔30分の間に、等間隔で10回測定して、平均をすれば良い。

しかし、現在のスケッチでは、1秒ごとに7回測定し平均している。レンタルサーバーにデータを送るとすぐに deep sleep する。 電気を節約するためである。 

理想的には、測定間隔30分の間に、等間隔で10回測定し、これらの間では deep sleep し、30分に1回平均処理と、WiFiをとおしてレンタルサーバーに送るのが良いとは思うが、スケッチが複雑になり過ぎて私には無理かもなあ。
一番大変なのは、一回分の測定値を、SPIFFSなどの不揮発性メモリーか、 外部のSDメモリか、deep sleep 中も電気が印加されているRTCメモリーに記憶する処理である。 5分ごとにレンタルサーバーに送ると電気をたくさん消費するからダメだ。

まず、SPIFFSに関する設計であるが、
SPIFFSはフラッシュメモリーなので、書き込み回数に寿命がある。
https://github.com/esp8266/Arduino/issues/2410
Winbond, the manufacturer of the flash chip for the ESP-12 series quotes a write endurance of "More than 100,000 erase/program cycles",
なので、10万回書き込みができる。
もし、1時間に10回データを書き込むと、1日に240回だから、400日は書き込みができる。
別の記事を読むと、やはり10万回と書いてある。

しかし、実験をした別の記事によれば、この10倍以上も耐久したと書いてある。
まあ、メーカー保証は一番厳しい場合なので、個人がホビーで使うなら保証値の10倍である10年は耐久すると考えてよいかもなあ。 私の場合は、SPIFFSメモリーが壊れて温度が見れなくなっても家族すら気が付かない。 孤独だ。

RTCメモリーは書き込み回数が無限であるが、揮発性なので電池を外すと消失してしまう。 しかし、今回の用途では、この消失は問題ない。なので、結論はRTC。 

でも、プログラミングはSPIFFSのほうが簡単そう。

電池の選択
まだ、実験が始まったばかりなのに、結論を出しました。
1.5Vリチウム乾電池です。
メリット ・ -10度という低温でも電気容量が低下せず、内部抵抗が上昇せず、安心。
・消耗しても1.2,  1.3V 以上を出力する。 逆に、アルカリは0.9V まで低下してしまう。 2本分の1.8V ではESP-12Eは動かない。つまりアルカリの寿命がかなり短い。

下図から判断すると、下限を1.2Vと仮定すると、リチウムの寿命はアルカリの3倍である。
さらに、低温特性が掛け算されると、リチウムの寿命はアルカリの10倍以上になる。

イメージ 27

デメリット ・消費電力が500mWと大きい場合は、リチウムはアルカリの倍以上もつが、今回の用途のように低電流では、両者の差は無いそうだ。 なのでかなり割高になる。 1本、200円。
・リチウムの初期電圧は1.8Vとかなり高い。 これが機器を破壊する恐れがある。 しかし、今回の用途では、ESP-12Eの最大許容は3.6Vなので、ぎりぎり大丈夫だ。

次点、充電式リチウム乾電池
メリット ・出力が1.5Vに安定化されている
デメリット ・1本、900円と高価。
・電子回路が入っているので、乾電池よりも故障は多い。 またこの電子回路の低温特性が不明。

総合判断すると
マイナス10度まで低下する寒冷地で、外気温を測定するという条件、
さらには、1年という長寿命という条件を満たすので、
リチウム乾電池が最適である。
しかも、乾電池というシンプルな部品は信頼性も高い。

ちなみに、1か月よりも頻繁に交換が必要なら、充電式リチウムイオン充電器が良い。

また、モバイルバッテリーは、deep sleep 時に出力しなくなる、 さらに出力時にLEDが無駄についているので今回の用途に向いてない。

--------------------------------------------------
測定状態は、3個とも正常である。
2018/11/11 8:00
イメージ 24

イメージ 25

イメージ 26

参考文献

ESP8266を電池で駆動するweb 記事はたくさんある。
このspecは、3.0 - 3.6V だが、
実際は、下側は2.2Vまで動くみたいだ。
40MHz にクロックダウンさせることで2.2Vでもフリーズしない。
ただし、電池の内部抵抗が大きいと開放電圧が3.0Vあってもダメだ。
内部抵抗がポイントである。
電気二重層コンデンサーも品番によっては、10オーム、 これは0.7Vも電圧降下してしまう。
だから内部抵抗が大きくて有名なCR2032を使う場合は、内部抵抗3オーム以下のコンデンサやスーパーキャパシタ、電気二重層コンデンサを電池と並列に、ESP-12Eのすぐ近くにつけないといけない。容量は0.2Fと馬鹿でかいのが必要になる計算だ。 
Q = C V = i t   C = i t / V = 0.07A x 1 sec / 0.3V = 0.2 F
現実、電気二重層コンデンサで内部抵抗が3オーム以下は寸法が大きく、高価だ。
そう考えると、1.5Vリチウムイオン乾電池は総合的に安価である。



ESP12E, HTTP AP 実験5

$
0
0

目的

WiFi APを利用し、 リモートかつワイヤレスで電圧を測る。
WiFi ルーターは使わない。

構成

A0 of ESP-12E --> WiFi AP of ESP-12E --> PC , スマホ

スケッチ

以前紹介したスケッチをマイナーチェンジした。

// WiFiAccesspointstaticIP2
// https://42bots.com/tutorials/esp8266-example-wi-fi-access-point-web-server-static-ip-remote-control/
// ESP8266 example: Wi-Fi Access point, static IP, web-server and read value of analog input A0
// Create a WiFi access point and provide a web server on it.
// For more details see http://42bots.com.
// 2018/10/21 : arranged for HiLetGo ESP-12E
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
IPAddress apIP(42, 42, 42, 42);  // Defining a static IP address: local & gateway
                                    // Default IP in AP mode is 192.168.4.1
/* This are the WiFi access point settings. Update them to your likin */
const char *ssid = "asakurasaya10";
const char *password = "asakurasaya10";
// Define a web server at port 80 for HTTP
ESP8266WebServer server(80);
void handleRoot() {
  char html[1000];
  int analogA0 = analogRead(A0);
  analogA0 = (int)(analogA0 + 10) / 10; //converting the 0-1024 value to a (approximately) percentage value
// Build an HTML page to display on the web-server root address
  snprintf ( html, 1000,
"<html>\
  <head>\
    <meta http-equiv='refresh' content='1'/>\
    <title>ESP8266 WiFi Network</title>\
    <style>\
      body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; font-size: 1.5em; Color: #000000; }\
      h1 { Color: #00AA00; }\
    </style>\
  </head>\
  <body>\
    <h3>Measure analog A0</h3>\
    <p>A0: %d%</p>\
  </body>\
</html>",
    analogA0
  );
  server.send ( 200, "text/html", html );
}

void handleNotFound() {
//  digitalWrite ( ledPin, 0 );
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for ( uint8_t i = 0; i < server.args(); i++ ) {
    message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
  }
  server.send ( 404, "text/plain", message );
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  Serial.println("Configuring access point...");
  //set-up the custom IP address
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));   // subnet FF FF FF 00 
 
  /* You can remove the password parameter if you want the AP to be open. */
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
 
  server.on ( "/", handleRoot );
  server.onNotFound ( handleNotFound );
 
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
}

結果

マイナーチェンジなので簡単にできた。
イメージ 1

イメージ 2

ESP-12E 環境センサ,電池駆動2

$
0
0

実験5  CR2032

ボタン型リチウムコイン電池CR2032による駆動実験をする。
これは、内部抵抗がとても大きいので、1個では電圧降下が大きすぎて、WiFiを使っているESP-12Eを駆動できないことがweb記事からわかっている。
そこで、並列接続にして、内部抵抗を小さくした
これをESP-12Eユニットの3.3V端子に印加した。WiFi として動作しているために消費電流が80mA ずっと流れている。

結果

CR2032の開放電圧   3.2V
80mA消費するESP-12Eユニット + CR2032 1 個   1.5V  駆動せず

80mA消費するESP-12Eユニット + CR2032 2 個   2.2V  駆動せず。 最初だけ1分以下駆動した

80mA消費するESP-12Eユニット + CR2032 3 個   2.5 から2.7V  駆動ok
   470uFを4個並列接続したが電圧は変わらず。予想していたとおりであった。
   30分駆動した
  

まとめ

CR2032を3個並列にすると、WiFiに接続した状態を継続できる
WiFiを接続した状態での駆動時間は30分であり短い。
したがって、CR2032は、WiFiを継続して使用するESP-12Eの駆動には実用的でない。。

しかし、断続的に消費する負荷の場合は電池寿命が長くなるために、今回の実験から単純に計算するよりも取り出せる電気量がずっと多くなる。 

したがって、deep sleep 動作を採用し、WiFi動作は30分に1回とか1日に1回なら実用的である。1F以上のコンデンサとの併用が理想的と思われる。 CR2032が1個と電気二重層コンデンサーで構成したdata logger のweb 記事がある。 なお、リチウムなので、低温には強いと思われる。

WiFiが動作する下限電圧は、2.3Vであった。

外付けコンデンサーに要求される内部抵抗は、0.6Ω以下と設計した


イメージ 1


イメージ 2


今後

CR2032 を3個並列接続で、ESP-12Eユニットをdeep sleep 動作させる実験は成功の可能性が高い。
さらに並列にコンデンサをつなぐと効果が大きい、なぜなら、CR2032は内部抵抗が大きいからである。
内部抵抗が、0.6以下 から  2.1 Ω以下のコンデンサなら並列接続の効果があるはずだ。
18 Ω以上なら効果が少ない。
しかし、電気二重層コンデンサの内部抵抗は集中定数ではなく分布乗数なので、計算値よりもずっと効果があるはずだ。 たとえば、今回のような内部抵抗の評価で10Ωであった場合、容量の一部は内部抵抗が1Ωということである。

容量は理想的には、1F以上。 0.1Fなら効果があるだろう。0.001F ( = 1000 uF ) でも効果があるというweb 記事がある。
寸法の大きさにも制限があるので、
内部抵抗が電気二重層コンよりもずっと小さいという理由で、 10000 uFの電解コンがいいかなあ
amazon で調べたら φ18 x H35である。 大きさがギリギリなのでこれより大容量は寸法的に無理。

電気二重層コンデンサは、内部抵抗が0.6Ω以下のは、寸法が大き過ぎる。悩むところである。

イメージ 6


イメージ 7

詳細データ


ESP-12Eに接続前   3.2V

接続     2.72V -->  内部抵抗 = (3.2 - 2.72)V / 0.08A = 6 Ω。
                                 意外と小さい --> 外付けコンデンサーはこの1/3 から 1/10以下が要求される。
                                  電池1個の内部抵抗は、 18Ω at 27mA
2 min          2.58V
5min           2.54V
10min         2.47V
15min          2.42V
20min          2.39V
25               2.34
30          2.32     Life of battery
35               1.99     WiFi  does not work
40               1.75
45               1.69     battery was removed from ESP-12E

connect again
55                2.81    
60                2.24    WiFi  does not work 
61                1.76    Though WiFi stopped , energy was consumed.  --> No good.
                             ESP-12E should be auto stopped , when battery voltage is lower than 2.3V.
65                1..46  


実験 1、3、4の結果  

アルカリ電池、モバイルバッテリ cheero CANVAS 、 リチウム充電電池


アルカリ電池とリチウム充電地、モバイルバッテリーで駆動していたESP-12Eは3台とも停止した。
アルカリ電池は11/4 20:00 から 11/15 2;00 10日と6時間駆動した。
0.96V at11/16  22:30

リチウム充電池は11/9 8:00 から 11/15 20:00 6日と12時間駆動した。
0.96V at11/16  22:30

モバイルバッテリーは11/7 0:00から 11/15 3:00  8日と3時間駆動した。
0.0V at11/16  22:30

短すぎる原因を調べるため
新しいアルカリに入れ替え、電流を測定した。
WiFi   80mA
deep sleep  9.5mA   <-- でかすぎる。こんなはずではなかった。

CdS 測定の差分   0.2mA  <-- 本来の deep sleep よりも大きい


アルカリ電池 11/15 早朝深夜にストップ
イメージ 3

リチウム充電池 動いているイメージ 4

モバイルバッテリー 11/15 早朝深夜にストップ
イメージ 5
            

ボタン電池  ESP-12E のE  start  11/16  0:30
deep 3.19V

アルカリ電池  ESP-12E のA  11/16  1:15
deep 2.63V

リチウム充電池  ESP-12E のB  start  11/16  1:15
deep 2.63V

ESP-12E 環境センサ,電池駆動3

$
0
0


実験 1、3、4の結果  

アルカリ電池、モバイルバッテリ cheero CANVAS 、 リチウム充電電池


アルカリ電池とリチウム充電地、モバイルバッテリーで駆動していたESP-12Eは3台とも停止した。
アルカリ電池は11/4 20:00 から 11/15 2;00 10日と6時間駆動した。
0.96V at11/16  22:30

リチウム充電池は11/9 8:00 から 11/15 20:00 6日と12時間駆動した。
0.96V at11/16  22:30

モバイルバッテリーは11/7 0:00から 11/15 3:00  8日と3時間駆動した。
0.0V at11/16  22:30

短すぎる原因を調べるため
新しいアルカリに入れ替え、電流を測定した。
WiFi   80mA
deep sleep  9.5mA   <-- でかすぎる。こんなはずではなかった。

CdS 測定の差分   0.2mA  <-- 本来の deep sleep よりも大きい


アルカリ電池 11/15 早朝深夜にストップ
イメージ 3

リチウム充電池 動いているイメージ 4

モバイルバッテリー 11/15 早朝深夜にストップ
イメージ 5
            
アルカリ電池  ESP-12E のA  11/16  1:15

リチウム電池  ESP-12E のB  start  11/16  1:15

--------------------------------------------------
ESP-12E のEは、回路を少し変え、
sketch を変えた。  sampling  1 sec x  7回  -->   10 sec x 30 回 = 5分
理由: 測定バラツキを減らすため。

29.68
41.13
988.34
665.07
connected to serverURL
GET /shangtianblog12E/sensorSet12.php?value=29.7&value1=41.1&value2=988.3&value3=665.1 HTTP/1.1
Host: databooster.stars.ne.jp
Connection: close
********  Closed  **********
- Sleeping for 1560 Seconds
- ZZZZZZZZZzzzzzzzzzzz z z z z z

考察


HiLetGo ESP-12Eは、電池駆動には向いてないと結論した。

理由
1. deep sleep モードでも8 - 9 mAの電流が流れる。
    これを減らす方法がnet にあるが、安定化電源ICを取り外したり、
    PCBの1mm以下の細い配線を切断するという、リスクがたくさんの作業である。

2. deep sleep で無い場合、WiFiを使って無くても 80mA 流れる。
    これは致命的である。解決する手段が無い。


他に適切8266は無いか?

ESP8266 のいろいろな製品を調べると、deep sleep の消費電流がいろいろあることがわかった。
英語の説明書には10uA と書いてあるし、確かに USB-UART 変換ICが違うので、deep sleep 時の消費電流が小さそうな気がする。
今回の実験に使ったESP-12Eを改造する記事もあるが、たいへんな作業なので、しない。
 
イメージ 1

イメージ 2

イメージ 3





ESP-12E 環境センサ,電池駆動4

$
0
0

目的

環境センサを電池駆動させる

経緯

HiLetGo ESP-12Eを電池駆動させることに成功した。
30分に1回WiFiに接続し、他の大部分はdeep sleepさせたが、アルカリ乾電池で10日しかもたなかった。
原因を調べたところ、deep sleepなのに 8mAも流れていた。そしてまさに私が使ったESP-12Eで同じく悩んでいるweb記事やYoutubeが見つかった。
原因は、USB接続用のIC とDDコンが使ってないときに電流を消費することだった。
最善の解決策は、dev board を使わないことだ。dev board には無駄が多い。
または、消費電流の小さな board を探すことだ。消費電流はboard メーカーによりまったくまちまちなのだ。

RUNNING NODEMCU ON A BATTERY: ESP8266 LOW POWER CONSUMPTION REVISITED

概要 : The two immediate suspects are the power regulator, and the UART, as discussed in the forum here.

イメージ 13

イメージ 14

または、Developement board を使わずに、ESP8266を使えばよかった。
でも、dev board でも低消費電流のboardがあるかもしれない。
ということで、5種類のboardを追加購入し、評価した。

・HiLetGoからの ESP8285
・Pinbotronix からの ESP8266
・Rasbee からの ESP8266-CH340G
・Rasbee からの ESP8266-CP2102
・DFRobotからの firebeetle esp32

をamazon.comで注文した。

HiLetGo と Pinbotronix は3日以内に入手できた。
Rasbee とDFRobot からは未だに入手できてない。中国から来る。


#193 Comparison of 10 ESP32 Battery powered Boards without display (incl. deep-sleep)

より。
deep sleepで400uA以下のboardは
  FireBeetle (DFRobot)
  TTGO
  Lolin32/Wemos

イメージ 15

Pinbotronix の ESP8266


イメージ 1

deep sleep で動作した。
deep sleep 時の消費電流は3から4mA であった。
1/2から1/3に少なくなったが、まったく満足できない。
目標は100uAだから。

ESP8285単体の電流は0.02mAなので、Dev boardがほとんどを消費している。


USB変換ICは、非動作時の消費電流が CP2102 より少ない CH340である。

計算では、アルカリ電池で、1か月駆動できることになる。 1.5V単三リチウム乾電池ならその1.5から2倍と単純計算されるが、ところが、我が町はマイナス10度まで下がるので、ベランダに設置するため 2,  3,  4,  5倍も差がひらくかもしれない。 なぜなら、アルカリ乾電池は寒さに弱いからである。

明日 2018/11/23 金 から初雪の天気予報である。 ここは、山形県、米沢市なので雪が多い。
例年よりも2週間遅い。

HiLetGo のESP-12E と非常に似てるので、移植が楽そうだ。

micro USB 5V ではRSTを制御できなかった。
合計 3.0 V 乾電池駆動では、D0 pinが RST 端子を駆動でき wake up でき、 deep sleep を成功できた。
けっこうぎりぎりなんだなあ。

イメージ 5



HiLetGoの ESP8285


イメージ 2

ダメ。基本的な動作がダメ
つまり、deep sleep から autoで目覚めないのだ。 原因は、RST pin のimpedance が低すぎて、GPIO16 pin で駆動できないのだ。 これは、board の設計ミスと断定できる。
いろいろ工夫したが、5時間を費やしたがダメだった。 おそらく FET で駆動すればいけるかもだが、上記のPinbotronix の ESP8266はちゃんと動いてるので、今後はこれをdeep sleep の電池駆動には使わない。

HiLetGoにmail したところ、
専門家のあなたにとって、この board の機能は限定されている。
との回答をもらい、私の評価方法は正しいわかった。
説明書にはdeep sleep のことも書いてあるので、正しくは虚偽なのだが、ホビーユースなので、まったく問題ない。 とにかく安価なので、こんなものかなあと思う。 100均で買ったものが壊れても文句を言わないのと同じ理由です。 逆に、もし、1個2000円もするものだったら、返品してますね。
このboardは deep sleep でautoでは起きないが、それ以外の用途には使える感じがしている。

deep sleep で眠らせて、 RST 端子を、 GND に短時間接触すれば 起き上がるので、 deep sleep 全部がダメというのではない。 autoで起きないのだ。


その欠陥を修正できる可能性が高い回路が下記である。
下図において、LEDとDの部分を取り除き、D2(GPIO06) をD0 に置き換え、回路定数を最適化すれば修正できると思っている。Tr , FETの選択が悪いと リーク電流が大きく、失敗する。

ESP8266, Deep Sleep mode test, wake up with a PIR motion detector

イメージ 11

イメージ 12

Rasbee の ESP8266-CH340G と ESP8266-CP2102

Rasbee は未だに入手できてない。

これは、Pinbotronix の ESP8266とそっーーーーーーくりなので、結果は、deep sleepは動くが、3 - 4 mAだろう。
目的を達成できないはず。
イメージ 3


これは、今まで長く評価してきた HiLetGo ESP-12E とそっーーーーーーーーくりなので、動作はするが、消費電流が大きいためにダメだろう。

イメージ 4



DFRobot の firebeetle esp32

かなり有望だ。 値段は、 HiLetGoの ESP8255 の 7倍もする。だからカタログに書いてあることは虚偽ではないと信じたい。
さて、下記 Fig の最後のほうに、まだbugは有るよと書いてある。 ESP32,  ESP8266 はどこから買っても bug があるのを承知しないといけないということですね。

ESP8266は、いつも6個から10個まとめて買っているのだが、これは1個4400円と高価なので、躊躇してしまい、2個しか発注しませんでした。 大人だけど、そんなに裕福ではない。 

イメージ 10


このBoardに関するYoutubeは、 DFROBOTのboard は0.06mA と小さい電流しか流れないことを実証している。


イメージ 6



イメージ 7


イメージ 8

これが証拠である。 deep sleep の間は、消費電流がたったの 60uAである。 HiLetGo ESP12-Eの 1/130 と小さい。 値段が高いだけのことはある。 設計も部品も優秀なのだと思う。
イメージ 9



SPECIFICATION
Working voltage: 3.3V
Input voltage: 3.3V~5V
Support electric current of low power consumption: 10 μA
Support USB charging.
Frequency: 240MHz
Wi-Fi standard:FCC/CE/TELEC/KCC
Bluetooth audio: the current under low power consumption of CVSD and SBC is 10μA
Working current: 80mA in average
Support one-key downloading.
Support micropython.
On-chip clock: 40MHz crystal and 32.768 KHz crystal.
Digital I/O: 10 (default setting of arduino)
Simulative input: 5(default setting of arduino)
SPI: 1 (default setting of arduino)
I2C: 1 (default setting of arduino)
I2S: 1 (default setting of arduino)
Working temperature: -40℃~+85℃
Dimension: 24 × 53(mm)/0.94 x 2.09(inches)
The dimension of mounting hole: inner diameter 3.1mm; outside diameter 6mm.

SHIPPING LIST
FireBeetle ESP32 IOT Microcontroller x1
18 pin-2.54mm x4
18 female header-2.54mm x4

本家website  ,  blog

sketch

Pinbotronix の ESP8266 で成功したsketch  
Blue LED は GPIO 2番

注意:sketch を書き込み終了して動き出したら、D0 とRST を接続。

#include <EEPROM.h>
// Time to sleep (in seconds):
const int sleepTimeS = 15;
byte analogOUTbefore = 0;
bool debug = true;
void setup()
{
          if (debug) Serial.begin(115200);
          if (debug) Serial.println("DeeplSleep test\n");
          if (debug) Serial.println("---------------");
  EEPROM.begin(1); // initialise EEPROM to store only one byte
          if (debug) Serial.println("- EEPROM inislised with 1 byte");
  pinMode(2, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
          if (debug) Serial.println("- Reading EEPROM at address 0");
  analogOUTbefore = EEPROM.read(0); // Read whatever value is in the EEPROM 0 byte
          if (debug) Serial.println("- previous A01 is: " + String(analogOUTbefore));
  for (int i = 0; i < 10; i++)
  {
    digitalWrite(2, HIGH);
    delay(500);
    digitalWrite(2, LOW);
    delay(500);
  }
  // EEPROM.write(addr, val);
  int analogOUT = 0;
  analogOUT = analogRead(A0);
  int deltaanalogOUT = 0;
  deltaanalogOUT = analogOUT - analogOUTbefore;
  EEPROM.write(0, analogOUT);
  EEPROM.commit();
          if (debug) Serial.println("- latest A01 is: " + String(analogOUT));
          if (debug) Serial.println("- Delta A01 is : " + String(deltaanalogOUT));

  delay(1000);
         
          if (debug) Serial.println("- Sleeping for "+ String(sleepTimeS) +" Seconds");
          if (debug) Serial.println("- ZZZZZZZZZzzzzzzzzzzz z z z z z\n");
  delay(1000); 
  ESP.deepSleep(sleepTimeS * 1000000);
 
  delay(1000);
}
// the loop function runs over and over again forever
void loop()
{
  //you aint seen me right?
}


ESP-12E 環境センサ,電池駆動5

$
0
0

目的


HiLetGo ESP-M2 を使って環境センサを半年間電池駆動させるための要素技術を開発する。
目標は、deep sleep 時の電流が、0.4mA = 400uA 
これは、WiFi接続が消費する電流と、時間平均が同じという計算である。
理想ではこれのさらに、数分の1で、100uA
   80mA x 10sec / 1800 sec = 0.4mA = 400uA  

前回の実験は ESP-12E を使って失敗した。 つまり、寿命が、100均アルカリ電池で、10日間駆動した。
目標は半年である。

---------------------------------------------
実験中
アルカリ電池
   start at 11/30 1:00

リチウム電池
   start at 12/01 3:30


さらにその次の目的は、放射線やガスセンサの測定値をいじくることである。
放射線は、ネットに公開すると喜ぶ人が多いと思う。 福島原発が廃炉工事をしている間は、放射性物質の漏洩があるだろう。しかもわが町、米沢市は福島原発からわずか100kmしか離れてない。 つい1か月前に、隣町の産直で売られていたきのこから規定値以上の放射能が検出され、販売してしまったきのこが回収された。 
 放射線量が高い地域に子供たちを歩かせているTVをドキュメンタリー番組で見たことがある。、あたかも安全な地域だと思わせたかったのだろう。 本当は風評ではない風評被害をかき消すために、子供たちの寿命を犠牲にした。  私は放射線1種を持っているし、原発関係の開発を8年経験している。 だから、そんな歪曲された現実に耐えられない。

また、冬季中は換気不足で毒ガスが部屋に溜まるので、アラートを音で鳴らすとか、Iphoneに送ると事故がへるはずだ。 こう考えると、家庭内でのIoTの応用は意外と少ない。

HiLetGoの ESP8285 ESP-M2


イメージ 1

イメージ 3


deep sleep 時の電流は、red LED 点灯で 3mA と少ない -->  Good 
red LEDをニッパデガリガリ削り取ったら deep sleep 時の電流が25uAと小さい。 こんなに小さくできるのか? とてもグレートである。
目標の400uAを大幅に達成した。 もう、他のboardを評価しなくてもいい。ああ、2万円も買ってしまったboardが何も評価されず放置されることになった。
HiletGo ESP-M2は米沢市まで納期が2日と早い。 これはほんとに助かります。 これとは反対に、スイッチサイエンスは米沢市には売ってくれないし、他メーカーは2週間もかかる。

評価回路
ESP-M2のADC (ADコンバータ) はESP-12Eと違って、 0 - 1 V である。1024分割。
問題:電池駆動だと電源電圧がだんだん低下していってしまう。 CdSを電池電圧に接続していたが、これはまずい。
対策: 定電圧をCdS回路に印加する。
定電圧回路: 2Vのツェナーダイオードの納期が2Wもかかるというのと、これは電池電圧が2,3Vまで低下したら機能しないと推測するからこれはダメと判断した。
そこで、赤LEDの順方向立ち上がり電圧Vfを利用する。下図。
順方向接続ですよ。ツェナーダイオードは逆方向接続です。 方向が逆なので注意をしてください。
Vfはバンドギャップなので温度が上がると徐々に狭くなる。 ダイオードの順方向電圧Vfの温度特性は -2mV/℃です。 -10 から +40 度の温度差で 0.10度Cである。 これは私の要求からすれば無視できるくらい小さい。
ちなみにこの温度係数を利用して温度計を作れるので、温度係数は大きいと認識するのが常識である。

イメージ 8


これで、ADコンバータの問題を解決したので、HiLetGo ESP-M2 で環境センサーユニットを組み立てていこうと思う。

ブレッドボードで回路の動作確認。
電流測定は、電池ボックスのケーブルと、ブレッドボード間に電流計を挿入した。
イメージ 2

基板に半田付け、組み立て

BME280の接続は、SCLにGPIO5、SDAにGPIO4をつなぐ。 VCCを3.3V,  GNDをGNDにつなぐ。
残り2端子は何もつながない。 このタイプはすでにプルアップ、プルダウンしてある。
I2Cのアドレスは
#define BME280_ADDRESS     (0x76)
SDOをVCC(3.3V)にプルアップすると、 (0x77) になる。 


イメージ 4

ソフトの総合的な動作確認OK    -->   電池寿命試験開始

アルカリ電池
start 11/30 1:00
電流測定、deep sleep 時 : 400 uA      --- 目標ギリギリ

         3000uF 電解コンのリーク     3uA
         BME280                 1uA
      CdS回路                 計ってないがLEDが点燈してないし、GPIO12がLOWなのでゼロのはず


考察 : テスト回路では25uAだったのに、P板に組み、スケッチをインストールしたら、16倍の400uAに増大してしまった。 P板のリークも考えられる。  超安物のP板を使っているから。日本製の1/10以下の安さです。
対策ができない。


結果: 目標をギリギリ満たしている。 ESP-12Eの20分の1であり、優秀である。 バッテリー駆動に向いている。
このため、バッテリー寿命試験を開始する。
前回は、アルカリ電池で、電池の寿命が10日間であったので、計算の上ではこの15倍に伸び、150日間になると予想する。つまり、電池の寿命は5月1日までと予想。 しかし、アルカリ電池は寒さに弱いのでどうなることやら。 豪雪地帯である山形県米沢市でフィールド試験ができるという幸運である。
リチウム電池は3割増しなので、195日後の、6月15日までもつと予想する。

それから、違うモデルのESPを購入中だが、入手しても評価しないかも。 なぜなら、新しいモデルの評価のためには、回路と、スケッチの修正が必要だからである。 ESP-M2 だけでいいと思う。

イメージ 5
 


イメージ 6

イメージ 7

スケッチ  : deep sleep 実験

// during deep sleeping , CdS value is stored in EEPROM
// Attention : EEPROM Write times be less than 100,000

#include <EEPROM.h>
// Time to sleep (in seconds):
const int sleepTimeS = 15;
int analogOUTbefore = 0;
int analogOUT = 0;
int deltaanalogOUT = 0;
void setup()
{
    Serial.begin(115200);
    Serial.println("DeeplSleep test\n");
    Serial.println("---------------");
    EEPROM.begin(2); // initialise EEPROM to store only one byte
    Serial.println("- EEPROM initialized with 2 byte");
    pinMode(14, OUTPUT);     // Initialize pin 14 to drive LED
    Serial.println("- Reading EEPROM at address 0");
    EEPROM.get(0,analogOUTbefore); // Read value stored in EEPROM address 0
    Serial.println("- previous A01 is: " + String(analogOUTbefore));
  for (int i = 0; i < 10; i++)
  {
    digitalWrite(14, HIGH);
    delay(500);
    digitalWrite(14, LOW);
    delay(500);
  }
   pinMode(12, OUTPUT);
   digitalWrite(12, HIGH);
   delay(100);
   analogOUT = analogRead(A0);
   delay(10);  
   digitalWrite(12, LOW);
   deltaanalogOUT = analogOUT - analogOUTbefore;
   EEPROM.put(0, analogOUT);
   EEPROM.commit();
   Serial.println("- latest A01 is: " + String(analogOUT));
   Serial.println("- Delta A01 is : " + String(deltaanalogOUT));
   delay(1000);
   Serial.println("- Sleeping for "+ String(sleepTimeS) +" Seconds");
   Serial.println("- ZZZZZZZZZzzzzzzzzzzz z z z z z\n");
   delay(1000); 
   ESP.deepSleep(sleepTimeS * 1000000);
 
   delay(1000);
}
// the loop function runs over and over again forever
void loop()
{
  //you aint seen me right?
}

ESP-12E 環境センサ,電池駆動6

$
0
0

目的


ESP8285 M2を利用した環境センサーに電池電圧の測定を追加する。

deep sleep 時の消費電流を0.4mAまで小さくできたので、アルカリ電池や、リチウム電池の寿命が5か月に長くなったと予測される。 そこで、電池寿命が来るのをブラウザで見られれば便利である。 

実験中
アルカリ電池
   start at 11/30 1:00

回路の改良

ESP8285(8266)はanalog input ( ADC , A0 ) を一つしか持っておらず、それはすでにCdS測定で使っている。
そこで、ダイオードを利用し、一つのADCで二つのanalog 値を読むようにする。

ダイオードは V f が小さいという理由で、ショットキーバリアダイオードを選んだ。 
動作点におけるI f は、相手側のダイオードの逆方向電流 I r だから、1mAである。 このときの V f はおそらく0.1V以下であろう。

1N5819
イメージ 3

回路図は下図の通りシンプルである。

参考website
   http://codelectron.com/4-ways-to-expand-adc-in-esp8266/
   4 Ways to expand ADC in ESP8266

AD変換の値を、電圧に変換するための換算係数は 0.00390 だった。 

イメージ 1



イメージ 4


イメージ 5


実験中
アルカリ電池
   start at 11/30 1:00

イメージ 2


ESP12E, HTTP AP 実験6

$
0
0

    ESP8266 ソフト アクセス ポイントの URL

目的

赤外線を利用した人感センサー HCSR501 のON,OFF信号を、アクセスポイントに設定したESP8266からWiFiの電波に乗せ、PCやスマホで読み取る。 
WiFiルーターは使わない。
このため、WiFiやLANの無いところでも、直接スマホから読み取れる。

人感センサー


イメージ 4



Pin配置
  公式websiteが見つからなかったが、Pin配置はこれらのwebsiteに書いてある。

イメージ 1

組み立て

人感センサーからの 01 出力をESP8266がデジタルで読み取る。
また、CdSの電圧を ESP8266のADコンバータ ( A0 ) で、10bitの分解能で読み取る。
これらの信号は、このESP8266にアクセスしたスマホやPCに送られる。

P板に半田付けすると、ブレッドボードよりもとても丈夫になり扱いが簡単になる。

イメージ 6

イメージ 7


スケッチを起動

イメージ 5



イメージ 2



イメージ 3


スケッチ

// ESP8266ajaxupdatepartofwebpage_r3.ino
/*
 * ESP8266 NodeMCU AJAX Demo
 * Updates and Gets data from webpage without page refresh
 * https://circuits4you.com
 *
 * WiFi AP
 // https://iot.keicode.com/esp8266/esp8266-ap.php
// ESP8266 をアクセスポイントとして Web サーバーを実装
// IoT のための電子工作入門
//
// ESP8266 をアクセスポイントとし明示的に IP アドレスを割り当てます。
// これによって、ESP8266 の IP アドレスが事前に分かります。
// ESP-12 Development Board を利用しました。*
 */
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include "index.h" //Our HTML webpage contents with javascripts
#define HCSR 0  // Motion Sensor
#define WIFI_SSID "asakurasaya1118"
#define WIFI_PWD "asakurasaya1118"
ESP8266WebServer server(80);
IPAddress ip(192,168,30,1);
IPAddress subnet(255,255,255,0);
//===============================================================
// This routine is executed when you open its IP in browser
//===============================================================
void handleRoot() {
 String s = MAIN_page; //Read HTML contents
 server.send(200, "text/html", s); //Send web page
}
void handleADC() {
 int a = analogRead(A0);
 String adcValue = String(a);
 Serial.println(adcValue);
 server.send(200, "text/plane", adcValue); //Send ADC value only to client ajax request
}
void handleHCSR() {
 int HCSR01 = 0;
 String HCSRstate = "OFF";
 HCSR01 = digitalRead(HCSR);
 if(HCSR01 == 1)
 {
  HCSRstate = "ON";
 }
 else
 {
  HCSRstate = "OFF";
 }
 Serial.println(HCSRstate);
 server.send(200, "text/plane", HCSRstate); //Send web page
 }
 
//==============================================================
//                  SETUP
//==============================================================
void setup(void){
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip, ip, subnet); 
  WiFi.softAP(WIFI_SSID, WIFI_PWD); 
 
  Serial.begin(115200);
  Serial.println("");
 
  pinMode(HCSR, INPUT);
  server.on("/", handleRoot);      //Which routine to handle at root location. This is display page
  server.on("/readADC", handleADC);
  server.on("/readHCSR", handleHCSR);
  server.begin();      //Start server
  Serial.println("WiFi soft AP started");
}
//==============================================================
//                     LOOP
//==============================================================
void loop(void){
  server.handleClient();          //Handle client requests
  delay(100);
}

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

index.h

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>
<div id="demo">
<h2>Data Logger by ESP8266 with Ajax</h2>
<h2>  --- CdS and IR Motion sensor ---</h2>
</div>
<div>
 analog A0 is : <span id="ADCValue">0</span><br>
        <br>
        Motion is : <span id="HCSRstate">NA</span><br>
</div>
<script>
setInterval(function() {
  // Call a function repetatively with 2 Second interval
  getData1();
  getData2();
}, 500); //500mSeconds update rate
function getData1() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("ADCValue").innerHTML =
      this.responseText;
    }
  };
  xhttp.open("GET", "readADC", true);
  xhttp.send();
}
function getData2() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("HCSRstate").innerHTML =
      this.responseText;
    }
  };
  xhttp.open("GET", "readHCSR", true);
  xhttp.send();
}
</script>
<br><a href="https://circuits4you.com">Circuits4you.com</a>
</body>
</html>
)=====";

ESP12E, HTTP AP 実験7

$
0
0

目的

ESP12E, http AP 実験6では、CdSのsignal と Motion sensor のstatus を 別々のAjax を使って取得していたが、このブログでは一回のAjax 通信で 両方の情報を取得するようにくふうした。
回線の使用頻度を半分にできた。逆に言うと、同じAjaxの使用回数で、2倍の頻度で CdSのsignalを取得できる。 

実際に、index.h   setInterval(function() {  において、 Ajax の取得間隔 }, 500);  を 100 に短くすると、改善前よりも早くなっているのを確認できた。 なお ハードウエアは 実験6とまったく同じである。

Motion sensor のstatusが "ON" の時には、 "ON" と表示し、 CdS signal の更新はしない。
Motion sensor のstatusが "ON" で無い時には、 CdS signal をAjaxでClient に送り、"OFF" と表示し、 CdS signal を更新する。

Motion sensor のstatusが "ON" の頻度はほとんど無いので、実用性は低下しない。

スケッチ

// ESP8266ajaxupdatepartofwebpage_r4.ino
//
// ESP8266 NodeMCU AJAX Demo
// Updates and Gets data from webpage without page refresh
// https://circuits4you.com
//
// WiFi AP
// https://iot.keicode.com/esp8266/esp8266-ap.php
// ESP8266 をアクセスポイントとして Web サーバーを実装
// IoT のための電子工作入門
//
// ESP8266 をアクセスポイントとし明示的に IP アドレスを割り当てます。
// これによって、ESP8266 の IP アドレスが事前に分かります。
// HiLetGo ESP-12E Development Board を利用しました。
//
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include "index.h" //Our HTML webpage contents with javascripts
#define HCSR 0  // Motion Sensor
#define WIFI_SSID "asakurasaya1118"
#define WIFI_PWD "asakurasaya1118"
#define RED_LED 16
#define GRN_LED 2
ESP8266WebServer server(80);
IPAddress ip(192,168,30,1);
IPAddress subnet(255,255,255,0);
//===============================================================
// This routine is executed when you open its IP in browser
//===============================================================
void handleRoot() {
 String s = MAIN_page; //Read HTML contents
 server.send(500, "text/html", s); //Send web page
}
void handleADC() {
 int a = analogRead(A0);
 String adcValue = String(a);
 Serial.println(adcValue);
 int HCSR01 = 0;
 String HCSRstate = "OFF";
 HCSR01 = digitalRead(HCSR);
 if(HCSR01 == 1)
 {
  HCSRstate = "ON";
  digitalWrite(RED_LED, 0);
  digitalWrite(GRN_LED, 1);
 }
 else
 {
  HCSRstate = "OFF";
  digitalWrite(RED_LED, 1);
  digitalWrite(GRN_LED, 0);
 }
 Serial.println(HCSRstate);
 if (HCSRstate == "ON") { adcValue = "ON" ;}
 server.send(200, "text/plane", adcValue); //Send ADC value only to client ajax request
}
 
//==============================================================
//                  SETUP
//==============================================================
void setup(void){
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip, ip, subnet); 
  WiFi.softAP(WIFI_SSID, WIFI_PWD); 
 
  Serial.begin(115200);
  Serial.println("");
 
  pinMode(HCSR, INPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(GRN_LED, OUTPUT);
  digitalWrite(RED_LED, 1);
  digitalWrite(GRN_LED, 1);
  server.on("/", handleRoot);      //Which routine to handle at root location. This is display page
  server.on("/readADC", handleADC);
  server.begin();      //Start server
  Serial.println("WiFi soft AP started");
}
//==============================================================
//                     LOOP
//==============================================================
void loop(void){
  server.handleClient();          //Handle client requests
  delay(100);
}


@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

index.h

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>
<div id="demo">
<h2>Data Logger by ESP8266 with Ajax</h2>
<h2>  --- CdS and IR Motion sensor ---</h2>
</div>
<div>
 CdS signal    is : <span id="ADCValue">0</span><br>
        <br>
        Motion status is : <span id="HCSRstate">NA</span><br>
</div>
<script>
setInterval(function() {
  // Call a function repetatively with 2 Second interval
  getData1();
}, 500); //500mSeconds update rate

function getData1() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      if (this.responseText == "ON"){
      document.getElementById("HCSRstate").innerHTML = "-ON-";
      }
      else {
      document.getElementById("ADCValue").innerHTML = this.responseText;
      document.getElementById("HCSRstate").innerHTML = "OFF";
      }

    }
  };
  xhttp.open("GET", "readADC", true);
  xhttp.send();
}
</script>
<br><a href="https://circuits4you.com">Circuits4you.com</a>
</body>
</html>
)=====";

参考にした website


Viewing all 83 articles
Browse latest View live