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

Excel VBA for Control Limit of non-normal distribution

$
0
0
key word : control chart, control limit, non-normal, nonnormal, percentile, statistical process control, Cpk, UCL, SPC , one-sided , skewed

Download
      version 418 
            download  download from another site

History and Background
I have been a data-miner since 2003. Before that I have been a researcher for electronic devices.  And I have also worked as a Statistician (2012 -  2013)  at a silicon wafer company.
During my two years of working as a statistician , I checked and reviewed several control limits calculated by a company's own software.  When I have a question about their calculation , I checked it by using the software. I use Minitab to double-check.  Usually , those difficult and complicated parameters are  non-normal.
All silicon wafer company need to deal with non-normal distribution parameters , for example metal contamination , anions , cations , and particles.  Those parameters are main causes of yield for semiconductors. 

Although the Minitab calculation method is usually a reliable IDI ( Individual Distribution Identification )  , it often does not work when the distribution is heavily skewed.  Sometimes control limit calculated by IDI is not suitable for process control.  If  we apply the control limit to historical data , more than 5% OOC occurred although theoretically OOC rate is only 0.27%.
But IDI works well for a slightly skewed parameters.
You can learn more about IDI by clicking this link: http://blog.minitab.com/.  

You can use a free trial of Minitab for 30 days.http://www.minitab.com/ja-jp/products/minitab/free-trial/
Regular price for one personal use is $1,595.
Student price is  \3,329  for 6 month rental

Another statistical package software is JMP (pronounce : jump) 
You can use a free trial of JMP for 30 days. https://www.jmp.com/ja_jp/download-jmp-free-trial.html
Regular price for one personal use is $1,785
Japanese  \289,440 including 8% tax.
Student price is  \105,840 including 8% tax.

JMP handles non-normal parameter in the same way as Minitab.  If the data is SKEWED, it needs to be transformed to normal distribution by looking for a function that will fit with the measured data.

Why does the IDI of Minitab and the corresponding tool of JMP not work for heavily skewed distribution ?
Best fit function which is selected by AD (Anderson-Darling) value and p-value by Minitab changes when duration of data changes or tool number changes , because those change is trivial ,the population should be the same.  And when the best fit function changes, both the control limit and the Cpk change.  Therefore IDI was not available for process improvement.   For example, we cannot know if the process has improved.
This is because IDI is over fitting and not robust. As a result IDI is not available for SPC when it is heavily skewed.  Because the best fit function is identified by data around average , data around tails have small effect.  But OOC% or Cpk is mainly decided by data around tails.   So there is a large mismatch between the best fit function and OOC%, Cpk.

Usefull usage of IDI :
I think that once you define best fit function of a parameter, you should not change the function.
This means that the smallest AD-value or the largest p-value is not the best to identify the best fit function..
Because if several data in a dataset are unstable a little, the best fit function may change.  But the function should be the same still.  This strategy is explained in JMP's guide. 

In 2013, I noticed that the right tail shows linear when non-normal data are plotted on a probability plot. I did not understand why. There are many  heavily skewed parameters that looks like a straight line on a probability prot.
So my idea is not based on a theory but based on a lot of experiences of reviewing hundreds of parameters and a thousand of charts.  And my idea works better than IDI , though its calculation is much easier than IDI.. 

Someday when I searched a better way than my idea. I found a patent created by TOSHIBA by chance.  Their idea is simple. That is , for non-normal parameter, a data those are larger than median is approximated by a normal distribution.  I thought that is very similar to my idea.

Most of the statistician can conclude that my idea is inspired by the TOSHIBA patent.  So my idea may be included in the TOSHIBA patent. This is their paper about it:https://yahoo.jp/box/E7KZ0o .

 Feature of my software
      Cons:
          *Easy to find and remove outlier
          *Normal distribution approximation.
              Fitting function is only normal distribution
          *Original solver for robust regression  --> High accuracy and calculation speed
          *Free

       Pros:
          *It needs a lot of data because only 16% of measured data are used for control limit calculation.
            For example: Control limit changed largely when we remove one maximum data as an outlier.
            It typically needs more than 100 data. If possible ,more than 300 data.

              Countermeasure
                - Multivariate method for control limit or outlier.   For example Taguchi MT , Hotelling T2.
                   This is my blog about Hotelling T2.   Sorry written in Japanese.
                         https://blogs.yahoo.co.jp/pironotakarabako/60939897.html

          *Doesn't show you confidence interval of control limit and Cpk
              Countermeasure
                Bootstrap
                   -  For example: re-sampling 1000 times from the raw dara by using Bernoulli trial
                   -  calculates 1000 control limits
                   -  calculate 2.5 and 97.5 %tile based on the 1000 control limit. These are confidence interval
                   -  But calculation above may needs long time. For example 10 min or 1 hour.  

           * Impact of a number of data to control limit and Cpk is not evaluated. 
              But in general , when it is larger than 300 , the confidence intervals are narrow and nigligible.
              In contrast , when it is less than 30 , the confidence intervals are too wide
             , and sometimes a conclusion made by my Macro is not available.
              Countermeasure
                - Also , multivariate method may help you.
                   If you deal with plural parameters at the same time , the number of data can increase.  

Feature of coding
          *Convinient data entry
          *Engin of robust regression is faster and more accurate than Microsoft Excel solver
  
イメージ 3




  
     A number of data should be over 100 or at least 30.

     Sometimes the control limit is not correct if is less than 30. So control limit can be too high or too low.

     Control limit can also be largely affected by the selection of outlier.

Method to find best fit normal-distribution-function
1. On a range larger than median  + σ; measured data are plotted on a probability plot.
2. Conduct linear regression analysis.
     -Strength of the robustness can be changed or selected by you.
     -Automatically weighted regression analysis.
3. An approximation straight line corresponds to the best normal function that fits.

Feature:
 -Normal function approximation
 -Range is the right tail where upper spec or upper control limit are located.
 -Calculated control limit and Cpk are robust because they are always approximated by normal function.
 -Those provided by Minitab IDI is not robust. It is also not available for indicator.
    Data around average or median are mainly used looking for the best function that fits.
    Spec and control limit does not exist.

       IDI Individual Distribution Identification: Select best function that fits.
       I think that IDI is over fitting. It doesn't fit with spec or control limit.
       Therefore mathematically it is interesting but practically meaningless.

イメージ 1





















イメージ 2





















          Z = 2.78 corresponds to 99.73%tile of one-sided parameter like above example..
          It corresponds to ( 1 - false alerm rate) of Xbar +- 3 sigma of double sided distribution. 


Excel VBA for Gauge R and R

$
0
0
key word : Gauge R and R , Gage R and R , GRR , P/V , P/T , MSA , Excel VBA , Excel macro , ANOVA

I'll provide you with a free Excel Macro which calculates Gauge R and R.

It is available for both Range method and ANOVA.

It is also available for double sided parameter and single sided parameter.
For example: Metal contamination and air particle.
I created the Gauge R and R Excel Macro (2009) 
Here is the link:  https://blogs.yahoo.co.jp/pironotakarabako/56466511.html

Feature of software
      *Both Range method and ANOVA
      *Available for single sided spec limit
      *Free
      *Easy to use
      *Coded using Excel VBA (Macro)
Feature of coding
   ・ANOVA.  not my coding , but copy.
    ・accurate.   Gauge R and R conclusions of over 10 dataset are verified with Minitab


イメージ 1

Formula of P/T and P/V

On double-sided ,  definition of P/T , P/V  following MSA 4th Edition is
   P/T = 6・σmeas / (USL - LSL)
       σmeas ^ 2 = σrepeat ^ 2 + σreproduce ^ 2
       σrepeat : repeatability , in many case , caused by equipment
       σreproduce : variation between operators
        USL , LSL : upper and lower specification limit

   P/V = σmeas / σprocess
        σprocess : σ of historical process data
        σprocess = (UCL - LCL)/6 is also available for P/V
        UCL , LCL : Upper control limit , Lower control limit



On one-sided ,  definition of  P/T , P/V
    P/T = 3・σmeas / (USL - μ) 
    P/V = 3・σmeas / (UCL - μ) 
     μ: mean of historical process data
     when heavily skewed distribution ,  μ should be exchanged with median. 

Python on server

$
0
0
目的:レンタルサーバーの上で、Pythonを動かす
経緯:直接 Python script  .py をserverの上で動かすのはいろいろとたいへんそうで、できなかった。
手段:そこで、phpから .py を呼び出す方法を試した
結果: phpを経由して、Python が格安レンタルサーバーの上で動いた。

使ったレンタルサーバー
  スターサーバー    プラン: エコノミー   月額:126円
  格安のレンタルサーバーでもPythonを動かせることがわかった

参考WEB記事
   Python を Web 上で使うには HOWTO

   python, ruby等のプログラム

       ロリポップレンタルサーバーでDjango?

レンタルサーバー会社からの情報
   コマンドパス  -->  結局使い方がわからなかった
      動かせなかった原因は AddHandler を設定するファイルを探せないからです。

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

うまく動いたscript と結果

PHP から Python のプログラムを実行させる方法について

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
call_python30.php
解説: $fullPath の内容を実行 exec して、戻り値を $outpara に入れる。
実行内容は、 python を、call_from_php30.py に作用させる。 
このとき call_from_php30.py に abcd   1234 を渡す。
call_from_php30.py による実行結果が、配列 $outpara に入れられて、call_python30.php に戻ってくる。
call_python30.php にて、 関数 echo で配列$outpara の値を表示する。 

<?php
// file name: call_python.php
    $fullPath = 
      'python call_from_php30.py abcd 1234';
    exec($fullPath, $outpara);
    echo '<PRE>';
    echo $fullPath;
    echo '<br>';
    echo $outpara[0];
    echo '<br>';
    echo $outpara[1];
    echo '<br>';
    echo $outpara[2];
    echo '<br>';
    echo $outpara[3];
    echo '<PRE>';
?>

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

# file name: call_from_php30.py
 
import sys 
 
if __name__=='__main__':
 
    print 'parameter1 is ' + sys.argv[1]
    print 'parameter2 is ' + sys.argv[2]
    print 'result is OK!'
    a = 2
    b = 3
    c = a * b
    print '2 * 3 = ' + str(c)

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

result
Python で 2 * 3 の計算をして、結果を 6 と正しく表示できた。
web上のserverでPythonを動かすことができた。


python call_from_php30.py abcd 1234
parameter1 is abcd
parameter2 is 1234
result is OK!
2 * 3 = 6

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

毎日決めた時刻にソフトを実行する方法

$
0
0
目的
毎日決めた時刻にソフトを実行させたい

条件
・管理者権限を持ってない
・自分で自由に設計できる
・無料

試したこと
・ Windows のスケジューラは使えなかった  <--  管理者権限を持ってない
・ベクターで調べたフリーソフト --> 目的に合うソフトが意外と無かった

見つけたソフト
指定した時間にバッチファイルを自動起動、実行する方法
毎日15時になったら『move.bat』を起動して実行
REM move.batを毎日15時に起動する
pause
pause
cd c:\aaa
at 15:00 /every:M,T,W,Th,F,S,Su c:\aaa\move.bat
pause

ESP8266で測定したデータを自動でグラフ描画

$
0
0
キーワード:  esp8266    esp32    wroom    IoT   arduino    jQuery   PHP

やりたいこと

測定データをサーバにアップし、PCやスマホでグラフを見たい

 例     
  sensor -->           ESP8266          -->        レンタル server   -->  ユーザーPC ,  スマホでグラフ表示 
                            Arduino IDE + WiFi shield

イメージ 5

参考にしたweb 記事



システム構成 概要

ESP8266    sensor_to_server.ino
           URLパラメーターとしてデータをGETメソッドでserverへ送る。
       セキュリーティーが低いけれど、趣味だからokだぜ
 ↓
wifi
 ↓  
レンタルserver --- StarServer  エコノミータイプ
        URL  :  http://databooster.stars.ne.jp/shangtianblog2/index.html
        sensorSet.php : URLパラメター  --> sensorLog.txt
 ↓
ユーザーの端末(PC , スマホ)
        jQuery
        index.js
            Ajax経由でserverからデータ sensorLog.txtをClientが取得する
                    sensorGet.php 
            Chart.bundle.min.js   -->  グラフを描画

システム設計で使う重要な設定値

8266に関する重要な設定値
  crystal freq    26MHz
  Upload speed   115200    -->  ソースコード内 および rs232C とあわせる
  バージョンは最新 2.4.2 で動く
  シリアルポート番号は、
      コントロールパネル デバイスマネージャー
      ポート(COMとLPT)    通信ポート( ??? )
  を見るとわかる
                                        Arduino IDE    8266用 設定値
イメージ 6

  
RS232C の設定
ソース:sensor_to_server4.ino

void setup() {
  // connection to PC with serial communication (RS232C)
  Serial.begin(115200);     <-- これをarduino IDEにあわせる
  connectWiFi();


8266から測定データをserverに送る周期の設定
delay 1000msec x 10回 + 計算時間 = 約10  sec
ソース:sensor_to_server4.ino
  while (count < 10) {
    analogOUT = analogRead(A0);
    average = average + analogOUT;
    sigma = sigma + analogOUT * analogOUT;
   delay(1000);
    count++;
  }

システム構成 詳細

esp8266のデバイスドライバーをArduino IDE にインストール
2018年8月現在の最新バージョン 2.4.2 で動いた
イメージ 1


arduino IDE で書いたソースをコンパイルし、8266にインストールが成功した
イメージ 2

イメージ 3

イメージ 4


IoT アプリ


こういうのを使うとプログラミングは楽になる
Blynk アプリで 遠方から スマホ とESP32 の双方向リアルタイム同時通信



ESP8266で測定したデータを自動でグラフ描画 続き

$
0
0
キーワード: ソースコード     esp8266    esp32    wroom    IoT    arduino    jQuery   PHP



イメージ 1


ESP8266 にインストールしたarduino で書かれたソース
sensor_to_server4.ino

// http://shangtian.hatenablog.com/entry/2017/06/16/223755
#include <ESP8266WiFi.h>
#include  <WiFiClient.h>
const char* ssid = "??????????";
const char* password = "??????????";
// host name of server
#define HOST_NAME     "databooster.stars.ne.jp"
// file path of PHP file
#define PHP_PATH      "/shangtianblog/sensorSet.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();
}
void loop() {
  // read analog input
  int analogOUT = 0;
  int count = 0;
  sigma = 0;
  average = 0;
  while (count < 10) {
    analogOUT = analogRead(A0);
    average = average + analogOUT;
    sigma = sigma + analogOUT * analogOUT;
    delay(1000);
    count++;
  }
  average = average / count;
  Serial.println ( average );
  sigma = sqrt( sigma / count - average * average );
  // end analog read
  connectServer();
  delay(10);
}
// 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(500);
    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  **********");
  }
}



sensorSET.php

<?php
header("Content-type: text/plain; charset=UTF-8");
date_default_timezone_set('Asia/Tokyo');

if (isset($_GET['value']))
{
  $value = $_GET['value'];
  $date = date("H:i:s");
  // sensorLog.txtにデータを保存
  file_put_contents("sensorLog.txt", $date .",".$value.",S00".PHP_EOL,FILE_APPEND);
$ret = sizeof(file("sensorLog.txt"));
if($ret > 30){
 $data = file("sensorLog.txt");
  unset( $data[0] ); //0行目を削除
 file_put_contents( "sensorLog.txt", implode($data) );
}
}
?>




sensorGet.php

<?php
// http://php-beginner.com/function/filesystem/file.html
echo file_get_contents("../shangtianblog/sensorLog.txt");

?>



index.htmlのコード

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="robots" content="noindex">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>Arduino & ESP-WROOM-02 & Sensor DEMO 2017/10/14</title>
 <link rel="stylesheet" href="css/normalize.css" />
 <link rel="stylesheet" href="css/index.css" />
 <script src="js/jquery-3.2.1.js"></script>
<!-- <script src="js/Chart.min.js"></script>  -->
 <script defer src="js/index.js"></script>
</head>
<body>
<!-- グラフ表示領域 -->
<div class="chart-container" style="position: relative ">
    <canvas id="chart"></canvas>
</div>
</body>
</html>



server からPC に送られてくる index.html にグラフを描画する Javascript を組み込む
https://qiita.com/kd9951/items/aece80abe0bd42b3b5d3
chart.js で複数軸の複合グラフを描く
注意:私は複合ではなく、単体のグラフを描きました



index.js

// PHPのURL   ******************************
var PHP_URL = "sensorGet.php";
// センサーの値
var sensorValue = 0;
var timeMes = "";
// サーバーにアクセス中かどうか
var isAjax = false;
// canvas要素の設定
var canvas = document.getElementById("chart");
canvas.width = window.innerWidth*0.9;
canvas.height = window.innerHeight*0.9;
var context = canvas.getContext("2d");
// 線の情報
var data = {
  labels: [],
  datasets: [
    {
      label: "temperature by esp8266",
      // 塗りの色
      fillColor: "rgba(220,220,220,0.2)",
      // 線の色
      strokeColor: "rgba(220,220,220,1)"    
    }
  ]
};
// グラフの描画設定
var options = {
  // アニメーションの速さ
  animationSteps: 10,
  // 線をベジェ曲線で滑らかにするかどうか
  bezierCurve: true,
  // 目盛を自分で設定する
  scaleOverride: true,
  // Y軸の目盛の数
  scaleSteps: 5,
  // Y軸の1目盛の大きさ
  scaleStepWidth: 100,
  // Y軸の最小値
  scaleStartValue: 0,
  // 目盛の色
  scaleLineColor: "#fff",
  // 目盛の線の幅
  scaleLineWidth: 1,
  // グリッドを表示するかどうか
  scaleShowGridLines: true,
  // グリッドラインの色
  scaleGridLineColor: "#222",
  // グリッドラインの幅
  scaleGridLineWidth: 1,
  // Y軸方向のグリッドを表示するかどうか
  scaleShowVerticalLines: false,
  scales: {
    xAxes: [{
       gridLines:{
         color: "#2f2f2f",
       },
       ticks: {
         fontColor: "#aaa",
         fontSize: 40,
         // labelFontSize: 20,
         maxRotation: 90,
         minRotation: 90,
         autoSkip: true,
       },
    }],
    yAxes: [{
       gridLines:{
         color: "#5f5f5f",
       },
       ticks: {
         fontColor: "#aaa",
         fontSize: 20,
       },
    }]
  },
};

// 折れ線グラフをインスタンス化
var chart = new Chart(context).Line(data, options);
setInterval(function() {
  // サーバーへアクセス中でなければ
  if(!isAjax) getSensorValue();
  isAjax = false;
  // グラフに値を描画
  chart.addData([sensorValue], timeMes);
 // wait
  const d1 = new Date();
    while (true) {
      const d2 = new Date();
      if (d2 - d1 > 100) {
        break;
      }
    }
  // データ数が30件超えたら古い1件を削除
  var len = chart.datasets[0].points.length;
  if (len > 30) {
    chart.removeData();
  }
}, 10000);
/**
 * PHPからセンサーの値を取得します。
 */
function getSensorValue() {
  // フラグをtrue
  isAjax = true;
  $.ajax({
    url: PHP_URL + "?p=" + new Date().getTime(),
    type: "post",
    dataType: "text",
    success: function(value) {
      timeMes = value.split(",")[0];
      // alert(timeMes);
      sensorValue = value.split(",")[1];
      console.log("Sensor Value : " + sensorValue);
      // フラグをfalse
      isAjax = false;
    },
    error: function(){
      console.log("Ajax could not get Sensor Value from server");
      isAjax = false;
    }
  })
}




HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでBlink

$
0
0
HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12E を2個で1480円で購入した。安い。普通に使える。

動作確認のために内蔵LEDで Blinkingをした。 Blinking でこんなにうれしい。


イメージ 1


イメージ 2

イメージ 3


イメージ 4

ソースコードはそのままで動く。
Blink.ino

/*
 ESP8266 Blink by Simon Peter
 Blink the blue LED on the ESP-01 module
 This example code is in the public domain
 
 The blue LED on the ESP-01 module is connected to GPIO1
 (which is also the TXD pin; so we cannot use Serial.print() at the same time)
 
 Note that this sketch uses BUILTIN_LED to find the pin with the internal LED
*/
void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  Serial.println(BUILTIN_LED); 
}
// the loop function runs over and over again forever
void loop() {
  Serial.println(BUILTIN_LED); 
  digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
                                    // but actually the LED is on; this is because
                                    // it is acive low on the ESP-01)
  delay(1000);                      // Wait for a second
  digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}

イメージ 5

BUILTIN_LEDは16でした。
なので
  digitalWrite(BUILTIN_LED, LOW);     -->     digitalWrite(16, LOW);
でも同じ動作をしました。
GPIO16は、下図、右上。 USER   WAKE
  

イメージ 6


イメージ 7

ESP8266でFTP その1

$
0
0
ESP8266,  ESP32 でFTPするにソースコードをさがす

<ESP-WROOM-02ワイヤレスカメラからYahoo!ジオシティーズへFTP転送>

ESPr DeveloperにFTPサーバー

Add FTP Client library #1183

FTP passive client for IDE v1.0.1 and w5100/w5200

WiFi FTP Client

RE: NEED HELP IN FTP CLIENT

ESP32 connects to FTP server

FTP Server for the ESP-WROOM-32




ESP8266でFTP その2

$
0
0
ESP8266でFTP その1 の続き

結果

8266 から file をレンタルサーバーであるNinja homepageへ送った。

イメージ 1

ソースコード

FTPESP8266r2.ino

/**
 * This file modifies SurferTim's FTP code (http://playground.arduino.cc/Code/FTP
 * to work with the esp8266 chip.This only contains the functionality to upload 
 * a file to your server but additional functionality could easily be added by 
 * modifying the code starting at line 148. Functionality would be implemented using
 * raw FTP commands. A list of such commands can be found at: http://www.nsftools.com/tips/RawFTP.htm
 * 
 * Posted 28 February 2017 by Patrick Duensing(fryguy128)
 * 
 * Add clock by using NTC Client   20170703
 */
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <FS.h>
#include <time.h>
#define FTPWRITE

//Change these variables to meet your needs
//#############################################
//Wifi
//I'm on a school network so I don't have a password,
//you'll have to modify the wifi connection if you have one.
const char *ssid = "002********4";
const char *password = "5******9";
#define JST   3600*9

//FTP stuff
const char* host = "ftp.homepage.shinobi.jp";
const char* userName = "databo*****to****";
const char* passwordFTP = "********";

//File Operation
char fileName[64] = "analog.txt";


//############################################
//DO NOT CHANGE THESE
char outBuf[128];
char outCount;
WiFiClient client;
WiFiClient dclient;

//###########################################
//Move into setup()
void setup() {
// Serial setup
  Serial.begin(115200);
  delay(100);
  Serial.print("\n\nReset:\n");
  
//Wifi Setup
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");    
  }
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
  
  //SPIFF setup
  SPIFFS.begin();
}

//#########################################
//Move into loop()
/*
 *In the current state, this loop will append
 *'Success!!' to the end of a filename then 
 *upload it to your FTP server
 */
 
void loop() {
  time_t t;
  struct tm *tm;
  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
  
  t = time(NULL);
  tm = localtime(&t);
  delay(1000);
  t = time(NULL);
  tm = localtime(&t);
  Serial.printf(" %04d/%02d/%02d(%s) %02d:%02d:%02d\n",
    tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
    wd[tm->tm_wday],
    tm->tm_hour, tm->tm_min, tm->tm_sec);
  delay(1000);

  
  int val = 0;
  val = val + analogRead(A0); 
  delay(1000);

  val = val + analogRead(A0); 
  delay(1000);

  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0); 
  delay(1000);
  
  val = val + analogRead(A0);
  delay(1000);
  
  val = val + analogRead(A0);
  delay(1000);

  val = val / 10;


  File f = SPIFFS.open(fileName , "w");   // a additional ,  w write
    if (!f) {
      Serial.println("file open failed");
    }
 
  f.printf(" %04d/%02d/%02d %02d:%02d:%02d",
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
        tm->tm_hour, tm->tm_min, tm->tm_sec);
  f.print(",AVG_Temp,");   // 1secx10 times
  f.println(val);
  f.close();

  if(doFTP()) Serial.println(F("FTP OK"));
  else Serial.println(F("FTP FAIL"));

  delay(3);
}

//#######################################
/*
 * This is the function where the magic happens.
 * all credit goes to SurferTim. This will open
 * and write the file to your FTP server
 */
byte doFTP()
{
    File fh = SPIFFS.open(fileName, "r");
    if (!fh) {
      Serial.println("file open failed");
    }
  if (client.connect(host,21)) {
    Serial.println(F("Command connected"));
  } 
  else {
    fh.close();
    Serial.println(F("Command connection failed"));
    return 0;
  }

  if(!eRcv()) return 0;

  client.print("USER ");
  client.println(userName);
  
  if(!eRcv()) return 0;
  
  client.print("PASS ");
  client.println(passwordFTP);
  
  if(!eRcv()) return 0;
  
  client.println("SYST");

  if(!eRcv()) return 0;

  client.println("Type I");

  if(!eRcv()) return 0;

  client.println("PASV");

  if(!eRcv()) return 0;

  char *tStr = strtok(outBuf,"(,");
  int array_pasv[6];
  for ( int i = 0; i < 6; i++) {
    tStr = strtok(NULL,"(,");
    array_pasv[i] = atoi(tStr);
    if(tStr == NULL)
    {
      Serial.println(F("Bad PASV Answer"));    

    }
  }

  unsigned int hiPort,loPort;
  hiPort=array_pasv[4]<<8;
  loPort=array_pasv[5]&255;
  Serial.print(F("Data port: "));
  hiPort = hiPort|loPort;
  Serial.println(hiPort);
  if(dclient.connect(host, hiPort)){
    Serial.println("Data connected");
  }
  else{
    Serial.println("Data connection failed");
    client.stop();
    fh.close();
  }
  
  client.print("STOR ");
  client.println(fileName);
  if(!eRcv())
  {
    dclient.stop();
    return 0;
  }
  Serial.println(F("Writing"));
  
  byte clientBuf[64];
  int clientCount = 0;
  
  while(fh.available())
  {
    clientBuf[clientCount] = fh.read();
    clientCount++;
  
    if(clientCount > 63)
    {
      dclient.write((const uint8_t *)clientBuf, 64);
      clientCount = 0;
    }
  }
  if(clientCount > 0) dclient.write((const uint8_t *)clientBuf, clientCount);

  dclient.stop();
  Serial.println(F("Data disconnected"));
  client.println();
 delay(10);    //  added this command for bug-fix on 201808
  if(!eRcv()) return 0;

  client.println("QUIT");

  if(!eRcv()) return 0;

  client.stop();
  Serial.println(F("Command disconnected"));

  fh.close();
  Serial.println(F("File closed"));
  return 1;
}

byte eRcv()
{
  byte respCode;
  byte thisByte;

  while(!client.available()) delay(1);

  respCode = client.peek();

  outCount = 0;

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);

    if(outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;      
      outBuf[outCount] = 0;
    }
  }

  if(respCode >= '4')
  {
    efail();
    return 0;  
  }

  return 1;
}


void efail()
{
  byte thisByte = 0;

  client.println(F("QUIT"));

  while(!client.available()) delay(1);

  while(client.available())
  {  
    thisByte = client.read();    
    Serial.write(thisByte);
  }

  client.stop();
  Serial.println(F("Command disconnected"));
}

ESP8266でFTP その3

$
0
0

目的

      8266 が FTP Client として機能するか調べる
      条件:FTP server は私のPCとする

システム構成

   8266 as FTP Client-->  私の部屋にあるWifi router  --> personal PC as FTP server
       つまり、すべてが私の部屋の中で完結する。 レンタルサーバーは使わない。

結果

FTPで送ることができた

イメージ 3

準備

    8266 を設定するためのpersonal PC (Client PC と呼ぶ)
      FTP server の代わりとなる personal PC
            これに FTP server 用の user name と password を作っておく
            つまり、コントロールパネルで             イメージ 2

作業手順

      Client PC 立ち上げ
      8266を Client PC のUSBに接続
      server PC 立ち上げ
      下記コード、コンパイル
      書きこみ
      8266 sketch data upload
      シリアルモニター  ON
 
イメージ 1

ソースコード

// rudi_FTP_Client_C.ino
// File: WiWi_FTP_Client.ino for ESP8266 NodeMCU
/*
   Original Arduino: FTP passive client 
   Modified 6 June 2015 by SurferTim

   You can pass flash-memory based strings to Serial.print() by wrapping them with F().

   2015-12-09 Rudolf Reuter, adapted to ESP8266 NodeMCU, with the help of Markus.
*/
#include <ESP8266WiFi.h>
#include <FS.h>

// comment out next line to write to SD from FTP server
#define FTPWRITE

// Set these to your desired softAP credentials. They are not configurable at runtime.
const char *ssid = "**********";   // <---  wifiの識別番号
const char *password = "53******";   // <---  wifiのpassword

boolean debug = false;  // true = more messages
//boolean debug = true;

// LED is needed for failure signalling
const short int BUILTIN_LED2 = 16;  //GPIO16 on NodeMCU (ESP-12)

unsigned long startTime = millis();

// provide text for the WiFi status
const char *str_status[]= {
  "WL_IDLE_STATUS",
  "WL_NO_SSID_AVAIL",
  "WL_SCAN_COMPLETED",
  "WL_CONNECTED",
  "WL_CONNECT_FAILED",
  "WL_CONNECTION_LOST",
  "WL_DISCONNECTED"
};

// provide text for the WiFi mode
const char *str_mode[]= { "WIFI_OFF", "WIFI_STA", "WIFI_AP", "WIFI_AP_STA" };

// change to your server
IPAddress server(192,168,1,21);  // <----  server PC のURL

WiFiClient client;
WiFiClient dclient;

char outBuf[128];
char outCount;

// change fileName to your file (8.3 format!)
String fileName = "TimeTemp.txt";  // <---  送るfile 名。 folder data の中に入っているfile 名
String  path = "/TimeTemp.txt";  //  <---  送るfile 名。 folder data の中に入っているfile 名のフルパス

// SPIFFS file handle
File fh;

void signalError() {  // loop endless with LED blinking in case of error
  while(1) {
      digitalWrite(BUILTIN_LED2, LOW);
      delay(300); // ms
      digitalWrite(BUILTIN_LED2, HIGH);
      delay(300); // ms
  }
}

//format bytes
String formatBytes(size_t bytes) {
  if (bytes < 1024) {
    return String(bytes) + "B";
  } else if (bytes < (1024 * 1024)) {
    return String(bytes / 1024.0) + "KB";
  } else if (bytes < (1024 * 1024 * 1024)) {
    return String(bytes / 1024.0 / 1024.0) + "MB";
  } else {
    return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
  }
}

//----------------------- WiFi handling
void connectWifi() {
  Serial.print("Connecting as wifi client to SSID: ");
  Serial.println(ssid);

  // use in case of mode problem
  WiFi.disconnect();
  // switch to Station mode
  if (WiFi.getMode() != WIFI_STA) {
    WiFi.mode(WIFI_STA);
  }

  WiFi.begin ( ssid, password );

  if (debug ) WiFi.printDiag(Serial);

  // ... Give ESP 10 seconds to connect to station.
  unsigned long startTime = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  // Check connection
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("WiFi connected; IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.print("WiFi connect failed to ssid: ");
    Serial.println(ssid);
    Serial.print("WiFi password <");
    Serial.print(password);
    Serial.println(">");
    Serial.println("Check for wrong typing!");
  }
}  // connectWiFi()

//----------------- FTP fail
void efail() {
  byte thisByte = 0;

  client.println(F("QUIT"));

  while (!client.available()) delay(1);

  while (client.available()) {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  client.stop();
  Serial.println(F("Command disconnected"));
  fh.close();
  Serial.println(F("SD closed"));
}  // efail

//-------------- FTP receive
byte eRcv() {
  byte respCode;
  byte thisByte;

  while (!client.available()) delay(1);

  respCode = client.peek();

  outCount = 0;

  while (client.available()) {
    thisByte = client.read();
    Serial.write(thisByte);

    if (outCount < 127) {
      outBuf[outCount] = thisByte;
      outCount++;
      outBuf[outCount] = 0;
    }
  }

  if (respCode >= '4') {
    efail();
    return 0;
  }
  return 1;
}  // eRcv()

//--------------- FTP handling
byte doFTP(boolean upload) {
  
  if (upload) {
    fh = SPIFFS.open(path, "r");
  } else {
    SPIFFS.remove(path);
    fh = SPIFFS.open(path, "w");
  }

  if (!fh) {
    Serial.println(F("SPIFFS open fail1"));
    return 0;
  }

  if (upload) {
    if (!fh.seek((uint32_t)0, SeekSet)) {
      Serial.println(F("Rewind fail"));
      fh.close();
      return 0;
    }
  }

  if (debug) Serial.println(F("SPIFFS opened"));

  if (client.connect(server, 21)) {  // 21 = FTP server
    Serial.println(F("Command connected"));
  } else {
    fh.close();
    Serial.println(F("Command connection failed"));
    return 0;
  }

  if (!eRcv()) return 0;
  if (debug) Serial.println("Send USER ftpuser");  // <---  server 用PC に登録した user name
  client.println(F("USER ftpuser"));

  if (!eRcv()) return 0;
  if (debug) Serial.println("Send PASSWORD ******");  //  <---  server 用PC に登録した user nameに対するpasswoord
  client.println(F("PASS ******"));  

  if (!eRcv()) return 0;
  if (debug) Serial.println("Send SYST");
  client.println(F("SYST"));

  if (!eRcv()) return 0;
  if (debug) Serial.println("Send Type I");
  client.println(F("Type I"));

  if (!eRcv()) return 0;
  if (debug) Serial.println("Send PASV");
  client.println(F("PASV"));

  if (!eRcv()) return 0;

  char *tStr = strtok(outBuf, "(,");
  int array_pasv[6];
  for ( int i = 0; i < 6; i++) {
    tStr = strtok(NULL, "(,");
    array_pasv[i] = atoi(tStr);
    if (tStr == NULL) {
      Serial.println(F("Bad PASV Answer"));
    }
  }
  unsigned int hiPort, loPort;
  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;

  if (debug) Serial.print(F("Data port: "));
  hiPort = hiPort | loPort;
  if (debug) Serial.println(hiPort);

  if (dclient.connect(server, hiPort)) {
    Serial.println(F("Data connected"));
  }
  else {
    Serial.println(F("Data connection failed"));
    client.stop();
    fh.close();
    return 0;
  }

  if (upload) {
    if (debug) Serial.println("Send STOR filename");
    client.print(F("STOR "));
    client.println(fileName);
  } else {
    if (debug) Serial.println("Send RETR filename");
    client.print(F("RETR "));
    client.println(fileName);
  }

  if (!eRcv()) {
    dclient.stop();
    return 0;
  }

  if (upload) {
    if (debug) Serial.println(F("Writing"));
    // for faster upload increase buffer size to 1460
//#define bufSizeFTP 64
#define bufSizeFTP 1460
    uint8_t clientBuf[bufSizeFTP];
    //unsigned int clientCount = 0;
    size_t clientCount = 0;
  
    while (fh.available()) {
      clientBuf[clientCount] = fh.read();
      clientCount++;
      if (clientCount > (bufSizeFTP - 1)) {
        dclient.write((const uint8_t *) &clientBuf[0], bufSizeFTP);
        clientCount = 0;
        delay(1);
      }
    }
    if (clientCount > 0) dclient.write((const uint8_t *) &clientBuf[0], clientCount);

  } else {
    while (dclient.connected()) {
      while (dclient.available()) {
        char c = dclient.read();
        fh.write(c);
        if (debug) Serial.write(c);
      }
    }
  }

  dclient.stop();
  Serial.println(F("Data disconnected"));

  if (!eRcv()) return 0;

  client.println(F("QUIT"));

  if (!eRcv()) return 0;

  client.stop();
  Serial.println(F("Command disconnected"));

  fh.close();
  if (debug) Serial.println(F("SPIFS closed"));
  return 1;
}  // doFTP()


void readSPIFFS() {
  fh = SPIFFS.open(fileName, "r");

  if (!fh) {
    Serial.println(F("SPIFFS open fail2"));
    return;
  }

  while (fh.available()) {
    Serial.write(fh.read());
  }

  fh.close();
}  // readSPIFFS()


void setup() {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  Serial.println("Sync,Sync,Sync,Sync,Sync");
  delay(500);
  Serial.println();
  // signal start
  pinMode(BUILTIN_LED2, OUTPUT);
  digitalWrite(BUILTIN_LED2, LOW);
  delay(100); // ms
  digitalWrite(BUILTIN_LED2, HIGH);
  delay(300); // ms

  Serial.print("Chip ID: 0x");
  Serial.println(ESP.getChipId(), HEX);

  Serial.println ( "Connect to Router requested" );
  connectWifi();
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("WiFi mode: ");
    Serial.println(str_mode[WiFi.getMode()]);
    Serial.print ( "Status: " );
    Serial.println (str_status[WiFi.status()]);
    // signal WiFi connect
    digitalWrite(BUILTIN_LED2, LOW);
    delay(300); // ms
    digitalWrite(BUILTIN_LED2, HIGH);      
  } else {
    Serial.println("");
    Serial.println("WiFi connect failed, push RESET button.");
    signalError();
  }

  if (!SPIFFS.begin()) {
     Serial.println("SPIFFS failed, needs formatting");
     signalError();
  }

  fh = SPIFFS.open(path, "r");
  if (!fh) {
    Serial.println(F("SPIFFS open fail3"));
    signalError();
  } else fh.close();
  
  Serial.println(F("Ready. Press d, u or r"));
}  // setup()


void loop() {
  byte inChar;

  if (Serial.available() > 0) {
    inChar = Serial.read();
  }

boolean upload = true; // false = download

  if (inChar == 'd') {
    upload = false;
    if (doFTP(upload)) Serial.println(F("FTP OK"));
    else Serial.println(F("FTP FAIL"));
  }
  
  if (inChar == 'u') {
    upload = true;
    if (doFTP(upload)) Serial.println(F("FTP OK"));
    else Serial.println(F("FTP FAIL"));
  }  

  if (inChar == 'r') {
    String fileNameDir;
    Dir dir = SPIFFS.openDir("/");
    while (dir.next()) {
      fileNameDir = dir.fileName();
      size_t fileSize = dir.fileSize();
      Serial.printf("FS File: %s, size: %s\n", fileNameDir.c_str(), formatBytes(fileSize).c_str());
    }
  }
  delay(10);  // give time to the WiFi handling in the background
}

ESP8266でFTP その4 通信プロトコル

$
0
0
テーマ:8266を使ったIoTに適したデータ通信プロトコルは何か?

ESP8266で実験したプロトコル

私は次のプロトコルを私の家で実験した。
HTTP , FTP , MQTT , WebSocket

適したプロトコル。私の実験の範囲内での判断

コーディングも、使うのも HTTP がすごく簡単だった。レンタルサーバーも当然100%対応している。しかし、私のPCに送るためには、私のPCに特別なソフトをインストールするので素人では無理。マニアなら普通にok、簡単である。

FTPは、私の別記事に掲載したソースコードを見ればすぐに分かるように、ソースコードが長い。しかし、汎用性はHTTPよりも広く、レンタルサーバはもちろん、私のPCにも送ることができる。
レンタルサーバに csv ファイルを FTPで送り、Clientから AJAXで取得すれば、レンタルサーバにPHPソフトを置かなくてもよい。つまり最低の機能のレンタルサーバでIoTシステムを組めるのである。

クラウドサービスを利用すれば、MQTTもWebSocketも簡単に使え、クラウドサービスのサーバーに簡単に送れた。 この理由は、クラウドサービスがESP32用のAPIを提供しているからである。
しかし、自分でレンタルサーバーのセットアップからするならセミプロ以上のスキルが必要。

適したプロトコル。一般的に言えるであろう予測。

クラウドサービスを使うなら HTTP POST と MQTTが主流みたい。

一方、自分で、レンタルサーバーをセットアップするならHTTP または  FTPが良い。

会社で使うなら、まずESP8266のハードとしての信頼性を評価すべきである。 PLCと比べれば寿命が短いに違いない。 
それでも会社で8266を使うというなら、少なくてもエージング試験をして初期不良のESP8266を破棄するくらいの対策はすべきだ。 
プロトコルの選択にすすむ。 
まず、測定からの時間遅れ、IT部門のスキル、クライアントのデバイスの機能によりどれもありうる。
ビッグデータ処理、統計処理のパーッケージソフトを使うならこれが指定しているプロトコルを使うことになる。

もし、今から会社の、またはある程度大きなシステムを作る場合。
データの構造が単純なら、 HTTP か FTP 、MQTT が良いだろう。
たとえば、温度と湿度を10分毎に送る場合である。

複雑でデータが大きいなら、FTP かHTTPが良いと思う。
たとえば、メッキ液の5種類のイオン濃度と、PHと液温度、メッキ液のレシピ番号、交換月日、メッキ液の原材料ロット番号などを、製品のロット毎に送る場合は csv ファイルをFTP で送るのが良い。 またcsv ファイルをExcel で閲覧、加工できるメリットはとても大きい。 データベースに格納するのがITの管理では有利だが、利用者が限定される。

IoTのプロトコルはまだまだ戦国時代であり、最終的に将来標準化されるプロトコルは予想がつかないが、HTTPは生き残るだろう。すべてのスマホとPCが備えているからである。
FTPはファイル転送に特化、限定したプロトコルであるため用途が少しずれるが、広く普及しているため、なくなりはしないと思う。 
レンタルサーバへのソースコードのアップロードはFTPが主流という現実は注目すべきである。

実際に仕事で携わったことのあるwebシステム

私はいくつかの会社でITシステムの一部を構築したことがある。
下記 2) , 3) はIoTでは無いが、技能は同じである。
おおまかにいえば、通信はHTTPが無難である。 
また、データ処理のソフトとしてExcelは必須なので、データ形式は、Excel またはcsv ファイルが無難な選択である。
統計処理やビッグデータをするならパッケージソフトやクラウドサービスを活用するのが良い。 自前で作るのはおろかである。お金が無くてもオープンソースの解析ソフトがある。これを使う自信がないならExcelだけでもokである。

1) 製造ラインの工程管理システム : FTP, Excel ファイル, csvファイル
    生産工程からデータを引き出し、データマイニングによる不良原因の特定や簡単な統計処理を実施。
    機械学習: 決定木、SVM、高度な重回帰分析により特性が悪い工程と装置番号を80%の精度で特定
    できた。
    現在(2018)も、似たようなシステムをある企業で担当しているが、残念ながらデータの収集のみであり、
         自動データマイニングのような高度な利用はしてないし、計画も無い。

2) 商品情報の共有:HTTP , ASP
    サーバー内にASPでプログラミングした。
    社員が複数の県にいたので、会議による共有ができなかった。
    結果、メールで商品情報を共有していたのをwebで可能にした。     
    情報の修正も容易に漏れなく共有できるようになった。

3) グループウェア: HTTP , ASP
    メンバーに希望日をwebに記入してもらい、会議実施日の決定をアシストをするソフト。
    それまでは、メールや電話でメンバーの都合を聞いていたが、手間がかかるためキーパーソンの
    都合だけをもとに会議の日時、工場を決めていた。
    結果、作業量は1/5に激減し、全員の都合をもとに会議の日時、工場を決めることができ
    るようになった。  決定がスピーディーになったため、似たような会議を統合することもで
    きるようになった。

ESP8266でFTP その5

$
0
0

結果

結果; Ninja ホームページに A/D 変換したデータを含んだファイル analog.txt を周期的に送っている。


イメージ 1


イメージ 2

ソースコード


FTPESP8266r14.ino

/**
   This file modifies SurferTim's FTP code (http://playground.arduino.cc/Code/FTP)
   to work with the esp8266 chip.This only contains the functionality to upload
   a file to your server but additional functionality could easily be added by
   modifying the code starting at line 148. Functionality would be implemented using
   raw FTP commands. A list of such commands can be found at: http://www.nsftools.com/tips/RawFTP.htm
   Posted 28 February 2017 by Patrick Duensing(fryguy128)
   Add clock by using NTC Client   20170703 H.Kakinuma
   add standard deviation    s = s + x*x   s =  sqrt(s/n - average~2 )
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <FS.h>
#include <time.h>
#define FTPWRITE
//Change these variables to meet your needs
//#############################################
//Wifi
//I'm on a school network so I don't have a password,
//you'll have to modify the wifi connection if you have one.
const char *ssid = "D80***********-2G";
const char *password = "22***********77";

#define JST   3600*9
//FTP stuff
const char* host = "ftp.homepage.shinobi.jp";
const char* userName = "da********r.a**t****a.jp";
const char* passwordFTP = "p******n";
//File Operation
char fileName[64];
int sec_previous;
//############################################
//DO NOT CHANGE THESE
char outBuf[128];
char outCount;
WiFiClient client;
WiFiClient dclient;
//###########################################
//Move into setup()
void setup() {
  // Serial setup
  Serial.begin(115200);
  delay(100);
  Serial.print("\n\nReset:\n");
  //Wifi Setup
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
  //SPIFF setup
  SPIFFS.begin();
}
//#########################################
//Move into loop()
/*
  In the current state, this loop will append
  'Success!!' to the end of a filename then
  upload it to your FTP server
*/
void loop() {
  time_t t;
  struct tm *tm;
  static const char *wd[7] = {"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat"};
  t = time(NULL);
  tm = localtime(&t);
  delay(100);
  t = time(NULL);
  tm = localtime(&t);
  Serial.printf(" %02d/%02d/%02d(%s) %02d:%02d:%02d\n",
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                wd[tm->tm_wday],
                tm->tm_hour, tm->tm_min, tm->tm_sec);
  delay(100);

  while (t < sec_previous + 60) {
    delay(500);
    t = time(NULL);
  }
  sec_previous = t;
  // read analog input
  int analogOUT = 0;
  int val = 0;
  int count = 0;
  int sigma = 0;
  while (count < 50) {
    analogOUT = analogRead(A0);
    val = val + analogOUT;
    sigma = sigma + analogOUT * analogOUT;
    delay(1000);
    count++;
  }
  val = val / count;
  sigma = sqrt( sigma / count - val * val );
  // end analog read
  t = time(NULL);
  tm = localtime(&t);
  delay(100);
  sprintf(fileName, "analog%02d%02d%02d%02d%02d%02d.txt", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  sprintf(fileName, "analog.txt");
  File f = SPIFFS.open(fileName , "a");   // a additional ,  w write
  if (!f) {
    Serial.println("file open failed");
  }
  f.printf("%04d/%02d/%02d %02d:%02d:%02d",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec);
  f.print(",AVG_Temp,");   // 1sec x coumt times
  f.print(val);
  f.print(",SIGMA_Temp,");   // 1sec x coumt times
  f.print(sigma);
  f.print(",count,");   // count
  f.println(count);
  f.close();
  if (doFTP()) Serial.println(F("FTP OK"));
  else Serial.println(F("FTP FAIL"));
  delay(10);
}
//#######################################
/*
   This is the function where the magic happens.
   all credit goes to SurferTim. This will open
   and write the file to your FTP server
*/
byte doFTP()
{
  File fh = SPIFFS.open(fileName, "r");
  if (!fh) {
    Serial.println("file open failed");
  }
  if (client.connect(host, 21)) {
    Serial.println(F("Command connected"));
  }
  else {
    fh.close();
    Serial.println(F("Command connection failed"));
    return 0;
  }
  if (!eRcv()) return 0;
  client.print("USER ");
  client.println(userName);
  if (!eRcv()) return 0;
  client.print("PASS ");
  client.println(passwordFTP);
  if (!eRcv()) return 0;
  client.println("SYST");
  if (!eRcv()) return 0;
  client.println("Type I");
  if (!eRcv()) return 0;
  client.println("PASV");
  if (!eRcv()) return 0;
  char *tStr = strtok(outBuf, "(,");
  int array_pasv[6];
  for ( int i = 0; i < 6; i++) {
    tStr = strtok(NULL, "(,");
    array_pasv[i] = atoi(tStr);
    if (tStr == NULL)
    {
      Serial.println(F("Bad PASV Answer"));
    }
  }
  unsigned int hiPort, loPort;
  hiPort = array_pasv[4] << 8;
  loPort = array_pasv[5] & 255;
  Serial.print(F("Data port: "));
  hiPort = hiPort | loPort;
  Serial.println(hiPort);
  if (dclient.connect(host, hiPort)) {
    Serial.println("Data connected");
  }
  else {
    Serial.println("Data connection failed");
    client.stop();
    fh.close();
  }
  client.print("STOR ");
  client.println(fileName);
  if (!eRcv())
  {
    dclient.stop();
    return 0;
  }
  Serial.println(F("Writing"));
  byte clientBuf[64];
  int clientCount = 0;
  while (fh.available())
  {
    clientBuf[clientCount] = fh.read();
    clientCount++;
    if (clientCount > 63)
    {
      dclient.write((const uint8_t *)clientBuf, 64);
      clientCount = 0;
    }
  }
  if (clientCount > 0) dclient.write((const uint8_t *)clientBuf, clientCount);
  dclient.stop();
  Serial.println(F("Data disconnected"));
  client.println();
  delay(10);   // add 201808
  if (!eRcv()) return 0;
  client.println("QUIT");
  if (!eRcv()) return 0;
  client.stop();
  Serial.println(F("Command disconnected"));
  fh.close();
  Serial.println(F("File closed"));
  return 1;
}
byte eRcv()
{
  byte respCode;
  byte thisByte;
  while (!client.available()) delay(1);
  respCode = client.peek();
  outCount = 0;
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
    if (outCount < 127)
    {
      outBuf[outCount] = thisByte;
      outCount++;
      outBuf[outCount] = 0;
    }
  }
  if (respCode >= '4')
  {
    efail();
    return 0;
  }
  return 1;
}

void efail()
{
  byte thisByte = 0;
  client.println(F("QUIT"));
  while (!client.available()) delay(1);
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }
  client.stop();
  Serial.println(F("Command disconnected"));
}

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでHello Server

$
0
0

目的

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12Eを web server に設定し、PCやスマホからのアクセスに対して Hello Server を返す。 またESP8266に搭載されているLED を点燈する。

動作

ESP8266 をHTTP server として設定し、WiFi ルーター経由で、PCやスマホのブラウザから8266にアクセスすると、ESP8266がいろんな応答をする。
これを応用すれば、スマホから、リアルタイムで、ESP8266を経由して、センサーの測定値をスマホに表示できる。 また、アクチュエータをコントロールして動かすことができる。
つまり、入力も出力も簡単にできてしまう。
HTTP server の機能はいろんな応用を与えてくれる。

イメージ 1


イメージ 2


イメージ 3



イメージ 4

イメージ 6



イメージ 5

イメージ 7


ソースコード

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
const char* ssid = "D8***********G";
const char* password = "2+++++++7";
ESP8266WebServer server(80);
const int led = 16;  // Builtin LED
void handleRoot() {
  digitalWrite(led, 0);
  server.send(200, "text/plain", "hello from esp8266!");
  delay(1000);   // builtin LED flash 1 sec
  digitalWrite(led, 1);
}
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(void){
  pinMode(led, OUTPUT);
  digitalWrite(led, 1);
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }
  server.on("/", handleRoot);
  server.on("/inline", [](){
    digitalWrite(led, 0);
    server.send(200, "text/plain", "this works as well");
    delay(1000);     // built in LED flash 1 sec
    digitalWrite(led, 1);
  });
  server.on("/on", [](){
    digitalWrite(led, 0);
    server.send(200, "text/plain", "LED on");
  });
  server.on("/off", [](){
    digitalWrite(led, 1);
    server.send(200, "text/plain", "LED off");
  });
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");
}
void loop(void){
  server.handleClient();
}

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでWeb Server

$
0
0

目的

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EをWeb Serverにして LEDを点燈する。

動作

前のブログ "HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでHello Server" とほぼ同じ。
ESP8266 をHTTP server として設定する。
PCやスマホのブラウザから、WiFi ルーター経由で、8266にアクセスする。
ESP8266のBuiltin LEDを点燈する。 GPIO16がLowで赤LEDがON。
GPIO12に設定し直せば青LEDがONする。

イメージ 1


イメージ 3






イメージ 2



イメージ 4


ソースコード

/*
 *  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 GPIO16 low, Red LED on.
 *    http://server_ip/gpio/1 will set the GPIO16 high.  LED off.
 *  server_ip is the IP address of the ESP8266 module, will be
 *  printed to Serial when the module is connected.
 */
#include <ESP8266WiFi.h>
const char* ssid = "D8*********2G";
const char* password = "2**********77";
// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);
void setup() {
  Serial.begin(115200);
  delay(10);
  // prepare GPIO2
  pinMode(16, OUTPUT);  // 
  digitalWrite(16, 0);
 
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
 
  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() {
  // 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(1);
  }
 
  // 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 GPIO2 according to the request
  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
}

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでEEPROM

$
0
0

目的

EEPROMの機能をテストしてみる

結果

address 0 から7 まで8個のaddressには、dummyデータ 123が書き込まれているのが読み取れました。
address 8 から19は何も書き込まなかったのでdefault の255が読みとれました。
address 20から23は EEPROM.begin(20); のように扱うaddressの対象外なので、メモリーに書き込まれている値ではなく、対象外であるという意味で 0 が表示されています。
以上で、 8266 が持っている EEPROM の基礎的な使い方がわかりました。

イメージ 1



ソースコード

値をEEPROMに書き込む

// eeprom_write.ino
// arranged for test
/*
 * EEPROM Write
 *
 * Stores values read from analog input 0 into the EEPROM.
 * These values will stay in the EEPROM when the board is
 * turned off and may be retrieved later by another sketch.
 */
#include <EEPROM.h>
// the current address in the EEPROM (i.e. which byte
// we're going to write to next)
int addr = 0;
void setup()
{
  EEPROM.begin(16);  // this test skech use 16 byte. Available for 512 byte.
}
void loop()
{
  // if Read(A0), need to divide by 4 because analog inputs range from
  // 0 to 1023 and each byte of the EEPROM can only hold a
  // value from 0 to 255.
  // this test skech sets 123 as constant value.
  int val = 123;   // analogRead(A0) / 4;
  // write the value to the appropriate byte of the EEPROM.
  // these values will remain there when the board is
  // turned off.
  EEPROM.write(addr, val);
  // advance to the next address.  there are 512 bytes in
  // the EEPROM, so go back to 0 when we hit 512.
  // save all changes to the flash.
  // this test skech use 16 byte , becaouse of  "EEPROM.begin(16);"
  addr = addr + 1;
  if (addr == 8)
  {
    addr = 0;
    EEPROM.commit();
  }
  delay(1000);
}



EEPROMに書き込んである値を読み出し、シリアルに表示する。

// eeprom_read.ino
// arranged for test
/*
 * EEPROM Read
 *
 * Reads the value of each byte of the EEPROM and prints it
 * to the computer.
 * This example code is in the public domain.
 */
#include <EEPROM.h>
// start reading from the first byte (address 0) of the EEPROM
int address = 0;
byte value;
void setup()
{
  // initialize serial and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  EEPROM.begin(20);
}
void loop()
{
  // read a byte from the current address of the EEPROM
  value = EEPROM.read(address);
  Serial.print(address);
  Serial.print("\t");
  Serial.print(value, DEC);
  Serial.println();
  // advance to the next address of the EEPROM
  address = address + 1;
  // looking at 24 bytes of EEPROM, from 0 to 23, so if we're
  // on address 24, wrap around to address 0
  if (address == 24)
    address = 0;
  delay(500);
}


参考となるweb site

It's well understandable.



HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでSPIFFS

$
0
0

目的

SPIFFSに書き込んだ files のリストが見たい

結果


これら8個のfiles をアップローダーで、PCから,  8266のSPIFFS に書き込んだ。
イメージ 3
イメージ 1


下のsketch を動かしたら、リストが見えた。アップロードした 8個のfile のfile name とサイズが表示された。

イメージ 2


ソースコード

// SPIFFS_FILENAME.ino
#include <FS.h>
 
void setup() {
  Serial.begin(115200);
  Serial.println("");
  SPIFFS.begin();
  String str = "";
  Dir dir = SPIFFS.openDir("/");
  while (dir.next()) {
    str += dir.fileName();
    str += " / ";
    str += dir.fileSize();
    str += "\r\n";
  }
  Serial.println(str);
}
 
void loop() {
  delay(100000);
}

文法、参考にしたweb記事



WIFI-TNGとESP-WROOM-02で始めるWIFI Arduino




HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでSPIFFS その2

$
0
0

目的

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12Eで、SPIFFSを使ったアプリをいじってみる

結果

このweb siteのソースコードをほぼ丸写しで実験してみた。

変更点:
LEDは16番。 LOW で点燈。
ブラウザーは、Chrome。 IEはダメだった、何でだろう。

イメージ 1

設計通り、PCのブライザーからLEDがON,  OFF した。

イメージ 2

イメージ 3


ソースコード

AJAX1.ino

// AJAX1.ino
// https://qiita.com/tadfmac/items/17448a2d96bd56373a66
// WIFI-TNG and ESP-WROOM-02 to make experiment WIFI Arduino
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h>
const char* path_root   = "/index.html";
const char* ssid        = "D8*********2G";
const char* password    = "2**********7";
const int BuiltinLED = 16;  // Builtin LED of HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12E
#define BUFFER_SIZE 16384
uint8_t buf[BUFFER_SIZE];
ESP8266WebServer server(80);
void handleRoot(){
  Serial.println("Access");
  server.send(200, "text/html", (char *)buf);
}
boolean readHTML(){
  File htmlFile = SPIFFS.open(path_root, "r");
  if (!htmlFile) {
    Serial.println("Failed to open index.html");
    return false;
  }
  size_t size = htmlFile.size();
  if(size >= BUFFER_SIZE){
    Serial.print("File Size Error:");
    Serial.println((int)size);
  }else{
    Serial.print("File Size OK:");
    Serial.println((int)size);
  }
  htmlFile.read(buf,size);
  htmlFile.close();
  return true;
}
void LedOn(){
  Serial.println("ON");
  digitalWrite(BuiltinLED,LOW);
  delay(1000);
  server.send(200, "text/html","OK");
}
void LedOff(){
  Serial.println("OFF");
  digitalWrite(BuiltinLED,HIGH);
  delay(1000);
  server.send(200, "text/html","OK");
}
void setup() {
  pinMode(BuiltinLED,OUTPUT);
  Serial.begin(115200);
  SPIFFS.begin();
  if(!readHTML()){
    Serial.println("Read HTML error!!");
  }
  WiFi.begin(ssid, password);
  WiFi.mode(WIFI_STA);
  Serial.println("Connecting to Access Point");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  if (MDNS.begin("wifi-home")) {
    Serial.println("MDNS responder started");
  }
  server.on("/", handleRoot);
  server.on("/on/", LedOn);
  server.on("/off/", LedOff);
  server.begin();
  MDNS.addService("http", "tcp", 80);   
}
void loop() {
  server.handleClient();
}


index.html
サブフォルダー data に入れる。
8266をUSBから外してまた入れる。
SPIFFSアップローダーで、PCから8266のSPIFFSにアップロードしておく。
イメージ 4
 
それから、 .ino をコンパイル。

<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<title>LED Button</title>
<style>
button{
  font-size:24px;
  width:50%;
  height:60px;
}
</style>
</head>
<body>
<script>
function sendOn(){
  send("/on/");
}
function sendOff(){
  send("/off/");
}
function send(url){
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.send();
}
</script>
<button id="on" onClick=sendOn()>LED ON</button>
<button id="off" onClick=sendOff()>LED OFF</button>
</body></html>

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12EでSPIFFS その3

$
0
0

目的

SPIFFSをもっといじってみたい。

結果

前回は、Wifiルーターを経由して、PCとESP32をつないだが、
今回は、Wifiルーターを経由せず、直接両者をつなぐ。

イメージ 2

inoファイルのコンパイルが終わると、
ワイヤレスネットワーク接続の画面に esp32server が表れるのでこれを選択する。
Wifiルーターを選んではいけない。

ESP32の IP アドレスは、 192.168.4.1 にデフォルトで決まっているらしい。
結果は、下図のように、SPIFFSに保存してあった index.html が ESP32 からPC にコピーされ、PCの画面に表示された。 Good.
イメージ 1


ソースコード

SPIFFS_SERVER.ino

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <FS.h>
const char *ssid = "esp32server";        //  ESP8266のサーバーに設定するID。 Wifiルーターではない
const char *pass = "esp32pass";      // 同じくpassword。 いずれも、8文字以上。
ESP8266WebServer Server(80); 
void handleNotFound() {
  if (! handleFileRead(Server.uri())) {
    Serial.println("404 not found");
    Server.send(404, "text/plain", "File not found in Dongbeino...");
  }
}
//  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";
}

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() {
  //
  SPIFFS.begin();
  //
  Serial.begin(115200);
  delay(100);      //  100ms
  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());
  // 
  Server.onNotFound(handleNotFound);  // 
  Server.begin();                     // 
}
void loop() {
  // 
  Server.handleClient();
}




index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <title>テーブルサンプル</title>
  </head>
  <body>
    <h1>テーブルサンプル</h1>
    <table border="1">
      <tr>
      <th>部署名</th>
      <th>計画</th>
      <th>売上</th>
      </tr>
      <tr>
      <td>本社</td>
      <td>1,400</td>
      <td>1,300</td>
      </tr>
      <tr>
      <td>大阪支社</td>
      <td>750</td>
      <td>920</td>
      </tr>
      <tr>
      <th>合計</th>
      <td>2,150</td>
      <td>2,220</td>
      </tr>
    </table>
  </body>
</html>

SPIFFSのその他の例

#include <FS.h>
SPIFFS.begin();
sprintf(fileName, "analog.txt");
File f = SPIFFS.open(fileName , "a");   // a additional ,  w write
  if (!f) {
    Serial.println("file open failed");
  }

  f.print(",AVG_Temp,");   // 1sec x coumt times
  f.print(val);
  f.print(",SIGMA_Temp,");   // 1sec x coumt times
  f.print(sigma);
  f.print(",count,");   // count
  f.println(count);
  f.close();

HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12Eで1行削除

$
0
0
目的: SPIFFSに保存してあるテキストファイルから第1行を削除する。
      応用すれば、たとえば 2行目を削除するとか、 3行目と6行目を削除するなどもできる。

結論
  sketchが完成した。しかし動作のエラーが多かった。

エラーの詳細
 ・8266のSPIFFSの上でのファイル書込み、書き換え操作はエラーがものすごく多い。
  
  エラーの発生頻度
  実験日 2018/9/21, 22
    実験したコンピュータ
       ・HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12E   
           エラー発生率 5 ~ 70%
           SPIFFSへの書き込みエラー多し
       ・スイッチサイエンス製ESP-WROOM-02開発ボード
            エラー発生率 50%
           renameでのエラー多し

  実験日 2018/9/23
    実験したコンピュータ
       ・HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12E   
           
           SPIFFSへの書き込みエラー
                              多し
                              2回同じデータを書き込むとエラーが無くなる
              1回の書き込みではbit当たりの電荷が足りないと推測する

                      .ino
              20回のテストでエラーなし。  -->  つかえるんじゃね?
              昨日と大きく改善されている。この原因が不明。
              PCを一度シャットダウンしたからか?

SPIFFSのエラー対策
 ・delay()をたくさん入れる   --- 必須
 ・usbケーブルを短くて抵抗の小さいのに交換した
 ・blue tooth など電波源を取り外した
 ・usbコネクターの位置を変えた
 ・以上でも完全な対策ではなかった  --> 電源系の安定化。低esr積層コンデンサ

まとめ
 ・SPIFFSに保存してあるテキストファイルから1行削除するsketchができた。
 ・8266のSPIFFSの上でのファイル書込みは同じデータで2回書き込むとエラーが減る。  
  実験したコンピュータ
     ・HiLetgo ESP8266 NodeMCU LUA CP2102 ESP-12E   
     ・スイッチサイエンス製ESP-WROOM-02開発ボード
    
今後
 テキストファイルから1行削除するsketchを応用して data logger のシステムを拡張しようとしたが、
  SPIFFS上でのファイル操作はエラーが発生した、不安定。
 
  確実なシステム構成は、8266はローカルPCやサーバーにデータを送るだけにして、これらでファイル
 操作をするシステムである。

 また、SPIFFSの可能な使い方は、たとえば index.html などのファイルを保存、内容を確認し、read だけ
 で使うという用途ならok。  これなら、SPIFFSの書き込みエラーの影響を回避できるし、 index.html を
 ソースコードに埋め込まなくてもすみ、SPIFFSを使うメリットが十分にある。

参考資料    
ESP8266が不安定だったけど解決した

ESP8266のSPIFFS機能



SPIFFSにdeletetest.txtを書き込み

ボードは Generic ESP8266 Module を使うと書き込みミスが少なかった。

イメージ 1

.inoをコンパイル書き込み

おなじ設定
イメージ 2


コード

// purpose of this sketch : to remove the first row from a text file stored in SPIFFS
// this sketch is still test version
// key point :  I put many delay() tp prevent error.

#include <FS.h>
void setup() {
   delay(1000);
   Serial.begin(115200);
   delay(500);
   if(!SPIFFS.begin()){
        delay(500); 
        Serial.println("An Error has occurred while mounting SPIFFS");
        return;
   }
   delay(500);
    // remove one row
    File original = SPIFFS.open("/deletetest.txt", "r");
    delay(500);
    File temporary = SPIFFS.open("/deletetesttemp.txt", "w+");
    delay(500);
    if(!temporary){
        Serial.println("-- failed to open temporary file ");
    }else{
        Serial.println("");
        String onerow = original.readStringUntil('\n')+"\n";
        delay(300);
        Serial.println("The first row of original file :");
        Serial.println(onerow);
        Serial.println("copy 2nd row of original to 1st row of temporary");
        delay(300);
        while(original.available()){
            String onerow = original.readStringUntil('\n')+"\n";
            delay(100);
            temporary.print(onerow);
            delay(100);
         }
         temporary.close();
         delay(100);
         // Serial.println("done copy to /deletetesttemp.txt");
    }
    original.close();
    delay(500);
 
   // remove original file
  delay(500);
  if(SPIFFS.remove("/deletetest.txt")){
     delay(500);
     Serial.println("Original file succesfully deleted");
   }else{
     delay(500);
     Serial.println("Couldn't delete file");
   }
   // rename teporal file to original name
   delay(500);
   if(SPIFFS.rename("/deletetesttemp.txt","/deletetest.txt")){
      delay(500);
      Serial.println("Succesfully renamed");
    }else{
      delay(500);
      Serial.println("Couldn't rename file");
    }
     
   // display "/deletetest.txt" on serial
   delay(100);
   File updated = SPIFFS.open("/deletetest.txt", "r");
   delay(100);
   if(!updated){
       Serial.println("Failed to open file for reading");
       return;
   }
   Serial.println("Content of updated file without the first row:");
   while(updated.available()){
       Serial.write(updated.read());
   }
   updated.close();
 
}
 
void loop() {}

Serial 出力の例

第一行目の 1aaaa が設計通り削除されている。
The first row of original file :
1aaaa
copy 2nd row of original to 1st row of temporary
Original file succesfully deleted
Succesfully renamed
Content of updated file without the first row:
2bbbb
3cccc
ddddd
eeeee
fffff
ggggg
hhhhh
iiiii
jjjjj
kkkkk
LLLLL
mmmmm
nnnnn





コード テスト用

// purpose of this sketch : to remove the first row from a text file stored in SPIFFS
// this sketch is still test version
// key point : because SPIFFS is very slow for read and write , I put many delay()
// therefore this sketch is very slow

#include <FS.h>
void setup() {
   delay(1000);
   Serial.begin(115200);
   delay(500);
   if(!SPIFFS.begin()){
        delay(500); 
        Serial.println("An Error has occurred while mounting SPIFFS");
        return;
   }
   delay(500);

   File file = SPIFFS.open("/deletetest.txt", "r");
   delay(500);
   if(!file){
        Serial.println("");
        Serial.println("Failed to open file /deletetest.txt for reading");
        return;
    }
    delay(100);
    // read a file and display data on serial
    Serial.println("");
    Serial.println("File Content:");
    delay(100);
    while(file.available()){
        delay(100);
        Serial.write(file.read());
    }
    delay(100);
    file.close();
    // remove one row
    File original = SPIFFS.open("/deletetest.txt", "r");
    delay(500);
    File temporary = SPIFFS.open("/deletetesttemp.txt", "w+");
    delay(500);
    if(!temporary){
        Serial.println("-- failed to open temporary file ");
    }else{
        Serial.println("");
        Serial.println("copy to /deletetesttemp.txt");
        delay(300);
        String onerow = original.readStringUntil('\n')+"\n";
        delay(300);
        while(original.available()){
            String onerow = original.readStringUntil('\n')+"\n";
            delay(100);
            temporary.print(onerow);
            delay(100);
         }
         temporary.close();
         delay(100);
         Serial.println("done copy to /deletetesttemp.txt");
    }
    original.close();

 
   // remove original file
  delay(100);
  if(SPIFFS.remove("/deletetest.txt")){
     delay(100);
     Serial.println("Old file succesfully deleted");
   }else{
     Serial.println("Couldn't delete file");
   }
   // rename temporal file to original name
   delay(100);
   if(SPIFFS.rename("/deletetesttemp.txt","/deletetest.txt")){
      delay(100);
      Serial.println("Succesfully renamed");
    }else{
      delay(100);
      Serial.println("Couldn't rename file");
    }
     
   // display "/deletetest.txt" on serial
   delay(100);
   File updated = SPIFFS.open("/deletetest.txt", "r");
   delay(100);
   if(!updated){
       Serial.println("Failed to open file for reading");
       return;
   }
   Serial.println("One row removed file content:");
   while(updated.available()){
       Serial.write(updated.read());
   }
   updated.close();
 
}
 
void loop() {}



Serial 出力の例 テスト用

第一行目の 1aaaa が設計通り削除されている。

File Content:
1aaaa
2bbbb
3cccc
ddddd
eeeee
fffff
ggggg
hhhhh
iiiii
jjjjj
kkkkk
LLLLL
mmmmm
nnnnn

copy to /deletetesttemp.txt
done copy to /deletetesttemp.txt
Old file succesfully deleted
Succesfully renamed
One row removed file content:
2bbbb
3cccc
ddddd
eeeee
fffff
ggggg
hhhhh
iiiii
jjjjj
kkkkk
LLLLL
mmmmm
nnnnn

HiLetgo ESP12EでBME280温湿度

$
0
0

目的:

HiLetGo BME280 と ESP12Eで温度 湿度 大気圧を計測する

測定結果

測定値は別に用意した高精度のセンサーで校正した。校正値はsketchに埋め込んだ。

BME280 test
-- Default Test --
Temperature = 27.35 *C
Pressure = 1025.98 hPa
Humidity = 55.40 %

Temperature = 27.42 *C
Pressure = 1025.96 hPa
Humidity = 53.95 %

Temperature = 27.37 *C
Pressure = 1025.92 hPa
Humidity = 54.85 %

Temperature = 27.35 *C
Pressure = 1025.98 hPa
Humidity = 55.19 %

手順:

Library 入手、PCにインストール
https://github.com/adafruit/Adafruit_BME280_Library
Clone or download で zipをダウンロード
解凍したフォルダーを、 library の下にコピー

イメージ 1
スケッチを取得
  ファイル --> スケッチ例  --> Adafluit   BME280 Library  -->  bme280test

ツールの設定  どちらでもokだった。 NodeMCU 0.9 も WeMOS D1 もokだった。
イメージ 8

イメージ 9

ライブラリー Adafruit_BME280.h を修正
  #define BME280_ADDRESS                (0x76)

結線

BME280 --> HiletGo ESP12E
SCL  -->  D1
SDA  --> D2
GND  -->  GND
VCC  -->  3.3V     注意:5Vもokとの記事があるが間違い。3.3Vにつなぐべし。

下図のように、CSB , CDOはそれぞれ VCC,  GNDにすでに基板上で 10Kオームを通してプルアップ、プルダウンしてあるので I2Cで使う場合は結線不要。
他メーカーの BME280ではプルしてないのがある。

イメージ 2


イメージ 7

イメージ 3

イメージ 4

イメージ 5

イメージ 6

スケッチ

/***************************************************************************
  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)
 ***************************************************************************/
#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;
void setup() {
    delay(1000);
    Serial.begin(115200);
    Serial.println();
    Serial.println(F("BME280 test"));
    delay(500);
    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 --");
    delayTime = 10000;
    Serial.println();
}

void loop() {
    printValues();
    delay(delayTime);
}

void printValues() {
    Serial.print("Temperature = ");
    Serial.print(bme.readTemperature() -2.8 );
    Serial.println(" *C");
    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();
}
Viewing all 83 articles
Browse latest View live