macsbug

Just another WordPress.com site

Archive for 11月 2015

ESP8266+BME280+IR LED+Air Con+ThigSpeak

leave a comment »

ESP8266+BME280+赤外線LEDでエアコンを自動化しThigSpeakに表示しました。    2015.12.01

この装置は、エアコンを買い替える事無く高機能化する事ができます。


寒くなるこのごろ、なんとかエアコンを自動化できないか。
我が家のエアコンは、温度設定くらいはできますが、室温をモニターしながらの動作が出来ないとか、
おはようボタンは 「これから6時間後に入る」で希望の時間を設定出来ず、使い物になりません。
そこで、BME280センサーで温度を検知し、赤外線LEDでエアコンを操作。
又、温度変化とエアコンの「暖房」「停止」状態を ThingSpeakでモニターできるようにしました。
日時(NTP)機能もあり、必要ならば希望の時間にエアコンをオンやオフにする事も可能です。
機能:日時(NTP)、温度、湿度、気圧の表示、エアコンの自動化、ThingSpeakでグラフ表示。


温度設定は、20〜21度(+-0.5℃)。この間でエアコンの「暖房」と「停止」を自動操作します。
結果:グラフに示すように、エアコンのオン・オフに合わせ1度の範囲で自動操作ができています。


準備:
以下の記事からハードを構成(ESP8266+BME280+OLED+NTP+赤外線LED+ThingSpeak)しました。
BME280    :ESP8266+BME280+OLED+BOX
OLED        :NTPcube ( ESP8266 + OLED )
NTP           :ESP8266 + NTPCliant  で時刻を取得し OLED に表示する
赤外線LED:赤外線LEDリモコンの制作Arduinoでリモコン作成(@eiKatou Blog氏に感謝)
_              リモコンデータを取得をする。私の場合は、RAR-3M1 HITACHI 日立 エアコンリモコン です。
ThignSpeak:ESP と BME280 と ThingSpeak で IOT


問題点:
1. ESP8266の容量不足:リモコンデータは、かなりメモリーを使用します。
_  2つの変数を使用していますが3つ使用すると動作せず多数のリモコンボタン機能は実現できません。
_  ESP8266は、Arduinoに比べ容量が多いと聞いていましたが条件によってはそうではありませんでした。
_  Arduino UNOでは、このような変数は1つしか使用できず、2つ以上ではメモリーオーバーになる。
_  スケッチの記述を工夫するか、SD CARD を使用すれば可能かも知れません。
2. エアコンの状態を直接モニターしていない為、誤動作を検知できない。
_  赤外線LEDの出力が何らかの原因で閉ざされた場合、信号が届かずエアコンの状態を把握できない。
_  エアコンのオン・オフ状態:スケッチでは最初にエアコンをオフし「オフ」と定義している。
_  何らかの原因で、エアコンのオン・オフの状態が変わるとスケッチは、誤解する。
3. 誤動作に対するスケッチの工夫が必要。たとえば、温度変化から状態をどうするかの判断をする。
4. 赤外線LEDの指向性は狭く、方向によってはエアコンで受信できない時があります。
5. 通常のリモコンと今回の装置によるエアコンの消費電力の差は調べていません。


感想:
1. リモコンは便利とはいえ、自動機能が無いとか、おはようボタンは6時間後とか不便です。
_  希望は自動的に23度に一定にして欲しいとか、朝の5時にオンして欲しいのです。
_  リモコンやスマホでコントロールできるとかは面倒で、環境をセンスして自動的にやって欲しい感じ。
2. エアコンの種類:年代やタイプによって機能が少ない物がある事と早々に交換する訳には行かない。
_  2015年最新式、デロンギの MD HEATER(75,000円)に示す ±0.5℃も可能です。
3. 現在のエアコンを買い替えずに高機能化できます。
4. エアコンの自動化を体験すると、実に気が楽になります。
5. 我が家の老朽化したアルミサッシの影響か外気温にもよりますが、30分後に1度下がっていますね。
6. 機能のグレードアップ:温度の設定をボタンで設定できるようにするとか、時間になったら動かすとか、
_  省エネ動作とか、しばらく使用してみて次の案を考えたいと思います。


スケッチ:


// NTP, TEMPERATURE, HUMIDITY, PRESSURE, AIRCON  // 2015.11.30
#include <ESP8266WiFi.h>                         // WiFi
#include <WiFiUdp.h>                             // WiFi
#include <Wire.h>                                //
#include <SPI.h>                                 //
#include <BME280_MOD_1022.h>                     // BME280
#include <Adafruit_GFX.h>                        // OLED
#include <ESP_Adafruit_SSD1306.h>                // OLED
#include <Time.h>                                //
#define OLED_RESET 4                             // OLED
Adafruit_SSD1306 display(OLED_RESET);            // OLED
extern "C" {                                     //
  #include "user_interface.h"                    //
}                                                //
char ssid[] = "xxxx";                            // your network SSID
char pass[] = "xxxx";                            // your network password
const char thingSpeakurl[] = "api.thingspeak.com";// THINGSPEAK URL
const char thingSpeakAPIKey[] = "xxxx";          // THINGSPEAK API
unsigned int localPort = 2390;                   // local port to listen
IPAddress timeServer(129, 6, 15, 28);            // time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48;                  // NTP time : first 48 bytes
byte buff[ NTP_PACKET_SIZE];                     // incoming outgoing packets
WiFiUDP udp;                                     // UDP:send & rx packets
long t = -6.32;                                  // BME280 Temp     offset
long h = +12.64;                                 // BME280 Humidity offset
long p = +5.52;                                  // BME280 Pressure offset
int  w = 32;                                     // wifi count
int  ac = 0;                                     // aircon mode 0=off, 1=on
float tempset  = 21.0;                           // Center Temp
float lo    = tempset - 0.5;                     // lower  temp
float hi    = tempset + 0.5;                     // upper  temp
float maxt  = tempset + 1.0;                     // max    temp
float mint  = tempset - 1.0;                     // min    temp
int cc = 5;                                      // max,min temp check count
int ir = 12;                                     // air conn pin no : GPIO_12
unsigned int acon[] = {335,167,43,124,44,43,40,43,41,44,39,44,40,43,40,
  43,40,43,40,43,40,43,40,43,40,43,40,125,44,42,40,43,40,43,40,43,40,
  43,40,43,40,43,40,43,40,43,40,44,39,43,40,44,40,44,40,45,38,45,39,43,
  41,43,40,125,43,43,40,125,43,124,43,125,43,124,43,125,43,124,44,43,
  40,125,43,125,43,124,44,124,43,124,44,125,42,124,43,125,42,125,43,44,
  40,43,40,44,39,43,41,43,40,43,40,43,40,43,40,43,40,43,40,125,44,124,
  43,43,40,43,40,125,43,125,43,124,44,124,43,44,40,44,40,125,43,124,43,
  43,40,43,40,44,40,125,43,43,40,43,41,126,40,43,40,43,40,125,43,124,
  44,43,40,125,43,124,43,43,40,125,43,124,43,43,40,125,43,124,43,43,40,
  44,40,125,43,43,40,44,39,43,40,44,40,43,41,124,44,124,44,43,40,125,
  43,125,43,124,44,43,40,43,40,124,43,43,40,43,40,124,43,125,43,40,43,
  125,43,124,44,43,40,125,43,124,43,43,40,43,41,124,44,42,41,43,41,44,
  40,45,39,43,40,43,40,43,40,44,40,124,43,125,43,124,44,124,43,124,44,
  124,44,124,44,125,43,43,40,44,40,44,40,44,39,43,40,43,40,43,41,43,40,
  125,43,125,44,123,44,125,43,124,44,124,43,124,44,124,44,43,40,43,40,
  44,40,44,40,43,40,43,40,44,39,44,40,125,43,124,44,124,43,125,43,125,
  43,124,44,124,44,124,44,43,40,43,40,44,40,43,40,43,41,43,40,43,40,43,
  41,125,42,125,44,123,44,124,44,124,43,124,44,125,43,124,43,43,40,43,
  40,44,40,44,40,43,40,43,41,44,39,44,39,125,43,125,43,124,43,125,43,
  124,44,124,43,125,43,124,44,43,40,125,43,124,44,43,40,43,41,125,42,
  43,40,44,39,125,43,43,40,43,40,125,43,124,44,43,40,125,43,124,44,124,
  43,40,43,43,40,44,40,125,43,43,40,125,43,124,43,43,40,125,43,124,44,
  124,44,43,41,124,43,43,40,43,40,44,40,43,40,43,41,43,40,45,39,43,40,
  43,40,43,41,124,44,124,43,125,43,124,44,124,43,125,43,124,44,124,43,
  43,40,43,41,44,39,43,40,43,40,43,40,43,40,43,41,124,44,124,44,124,43,
  124,43,124,44,125,43,125,43,124,43};           // Air con (Heating)
unsigned int acoff[] = {336,167,43,125,43,41,42,41,43,41,42,41,42,41,
  42,41,43,41,42,41,43,41,42,41,42,41,44,124,43,41,42,41,42,41,42,41,
  43,41,43,41,42,41,43,41,42,41,43,40,43,41,43,41,42,41,42,41,43,40,43,
  42,42,41,43,125,43,41,43,124,43,125,44,124,43,125,43,126,42,125,43,
  41,43,125,42,125,43,125,42,125,43,125,43,125,43,125,43,125,43,125,43,
  41,42,41,43,41,43,41,42,41,43,41,42,41,42,41,43,41,43,41,42,125,43,
  126,42,41,42,41,42,125,43,125,43,125,43,125,43,41,42,41,43,125,43,
  125,42,41,42,41,42,41,43,125,43,41,43,41,42,125,43,41,42,41,42,125,
  43,125,42,41,42,125,43,125,42,41,42,125,43,125,43,40,42,125,43,125,
  43,41,42,41,42,125,43,41,42,41,42,41,43,41,42,41,43,125,43,125,43,
  40,43,125,43,125,42,125,43,40,43,41,42,125,43,41,42,41,43,125,43,
  125,42,41,42,125,43,125,42,41,42,125,43,125,43,40,43,41,43,125,43,
  40,43,41,42,41,42,41,42,41,43,44,40,41,43,41,43,125,43,125,44,124,
  43,125,42,125,42,125,43,124,43,125,42,41,42,41,43,44,40,41,43,41,
  42,42,42,41,43,43,40,125,43,125,44,124,44,124,43,124,43,124,43,124,
  43,124,43,40,43,41,42,41,42,41,43,41,43,41,43,40,43,41,43,125,43,
  124,44,124,43,124,43,125,43,124,44,124,44,124,43,41,43,41,43,41,42,
  41,43,40,43,41,42,41,42,41,43,125,43,124,44,124,43,124,43,125,43,
  124,44,125,43,124,44,40,43,41,42,41,43,41,43,41,43,40,43,41,43,41,
  42,125,43,125,43,124,43,124,43,124,43,124,43,125,42,125,43,40,43,
  125,43,124,44,40,43,41,42,125,43,42,42,41,42,125,43,41,42,41,42,
  126,42,125,43,40,43,124,43,124,43,124,43,40,43,41,42,41,43,41,43,
  40,43,125,43,125,43,40,43,125,43,125,43,124,43,125,43,125,43,40,43,
  41,43,41,43,41,42,41,43,41,43,40,43,43,40,41,43,41,43,125,43,124,44,
  124,43,125,43,124,44,124,43,124,44,124,43,41,42,41,42,41,43,43,40,
  41,42,41,42,42,42,41,43,125,43,124,44,124,43,124,44,124,44,
  124,43,125,43,125,43};                         // Air Con (STOP)

void setup(){
  //Serial.begin(115200);
  pinMode(ir,OUTPUT);digitalWrite(ir,LOW);       // AirCon Pin off
  //---------------------------------------------// OLED SETUP
  Wire.begin(13, 14); delay(10);                 // I2C SDA,SCL
  display.begin(SSD1306_SWITCHCAPVCC,0x78>>1);   // I2C_ADDRESS
  display.clearDisplay();                        // all pixels off 
  display.setTextSize(1);                        // font sizes 1 to 8
  display.setTextColor(WHITE);                   // WHITE,BLACK,INVERSE
  display.setCursor(0,0);                        // location x,y
  display.display();                             // plotted items
  //---------------------------------------------// NTP WIFI SETUP
  display.print("Mac ");                         //
  display.print(WiFi.macAddress());              // Mac Address
  display.print("Connecting to ");               //
  display.println(ssid);display.display();       //
  WiFi.begin(ssid, pass);                        //
  while (WiFi.status() != WL_CONNECTED){         //
    delay(500);display.print(WiFi.status());     //
    display.display(); w--;                      //
    if (w<0){display.print("fail");              //
      display.display();goto p;}                 //
  }                                              //
  display.println("ok"); display.print("IP: ");  //
  display.println(WiFi.localIP());               //
  udp.begin(localPort);                          //
  display.print("Local port: ");                 //
  display.println(udp.localPort());              //
  display.display();                             //
  //---------------------------------------------// ThingSpeak check
  display.println("Connecting to ..");display.display();//
  connectWiFi();                                 // ThingSpeak conn
  display.println("Connecting ok");display.display();
p:delay(2000);
  //---------------------------------------------// BME280 Setup
  BME280.readCompensationParams();               // read NVM
  BME280.writeOversamplingTemperature(os1x);     // 1x over sampling
  BME280.writeOversamplingHumidity(os1x);        // 1x over sampling
  BME280.writeOversamplingPressure(os1x);        // 1x over sampling
  //---------------------------------------------//
  aircon_off();                                  // aircon off
}                                                //

void loop(){                                     //
  // --------------------------------------------// NTP
  if ( w > 0 ){                                  // with wifi ok
  sendNTPpacket(timeServer);delay(1000);         // send NTP server
  int cb = udp.parsePacket();                    // packet check
  if (!cb) { dispset(1,"no packet yet");}        // no packet
  else {                                         // packet ok : UTC
    udp.read(buff, NTP_PACKET_SIZE);             // read packet buffer
    unsigned long hW = word(buff[40],buff[41]);  // hiWord
    unsigned long lW = word(buff[42],buff[43]);  // lowWord
    unsigned long secsSince1900 = hW << 16 | lW; //
    const unsigned long seventyYears=2208988800UL;// NTP  time
    unsigned long t=secsSince1900-seventyYears;  // Unix time:
    t = t + 32400;                               // JST=UTC+9(9*60*60)
    setTime(t);                                  // Time set
    dispset(2,"");                               // date,time display
    display.print(year()); display.print('/');   // year
    display.print(month());display.print('/');   // month
    display.println(day());display.display();    // day
    display.setTextSize(4);display.setCursor(0,30);// UTC time at GMT 
    if (((t % 86400L)/3600)<10){display.print('0');}
    display.print((t % 86400L)/3600);            // hr
    display.print(':');                          //
    if (((t % 3600)/60)<10){display.print('0');} //
    display.println((t % 3600)/60);              // minute
    display.display();                           //
  }                                              //
  delay(5000);}                                  // end of with wifi ok 
  //---------------------------------------------// BME280
  BME280.writeMode(smForced);   delay(50);       // chip goes back to sleep
  while (BME280.isMeasuring()){;delay(50);}      // Measurering check
  BME280.readMeasurements();                     // read out the data
  float  t_  = BME280.getTemperature() + t;      // Temp     data
  String temp=String(t_);                        // Temp     data
  String humi=String(BME280.getHumidity() + h);  // Humidity data
  String pres=String(BME280.getPressure() + p);  // Pressure data
  //---------------------------------------------// OLED
  ALL( 2, temp, humi, pres);                     // All  Display
  THP( 4, temp, 2, "    C");                     // temp Display
  //---------------------------------------------// airconn cont,with limit
  if ( ac == 0 && t_ <= lo ){dispset(4,"AC ON"); // <=low_temp,aircon on
    aircon_on(); ac = 1; delay(3000);            // aircon on, on mode
  }                                              //
  if ( ac == 1 && t_ >= hi ){dispset(4,"AC OFF");// >=hi_temp,aircon off
    aircon_off(); ac = 0; delay(3000);           // aircon off, off mode
  }                                              //
  //---------------------------------------------// max,min limit
  if ( t_ <= mint | t_ >= maxt ){ cc-- ;}        // max or min counter 
  if ( t_ <= mint && cc > 0 && ac == 1 ){        // minimum action
    dispset(4,"AC ON"); aircon_on();             // min_temp,aircon on
    ac = 0; cc = 5; delay(3000);                 // on mode,counter reset
  }                                              //
  if ( t_ >= maxt && cc < 0 && ac == 0 ){        // maxmum action
    dispset(4,"AC OFF"); aircon_off();           // max_temp,aircon off
    ac = 1; cc = 5; delay(3000);                 // off mode,counter reset
  }                                              //
  String ap = String( ac,DEC);                   // aircon mode on/off
  //---------------------------------------------// OLED
  THP( 4, humi, 2, " %");                        // humi Display
  THP( 4, pres, 0 ," hpa");                      // pres Display
  //---------------------------------------------// ThingSpeak
  if ( w > 0 ){                                  // with wifi ok
  dispset(1,"connection ThingsPeak");            //
  connectWiFi();                                 // ThingSpeak connect
  dispset(0,"connection ok        ");            //
  updateThingSpeak( "1=" + temp + "&2=" + humi   // data to ThingSpeak
                 + "&3=" + pres + "&4=" + ap );  // Field1,2,3,4
  dispset(0,"Transmit ThingsPeak");delay(2000);  //
  }                                              //
  //---------------------------------------------// OLED 
  ALL( 2, temp, humi, pres);                     // All Display
  //---------------------------------------------//
  delay(60000UL);                                // 1 min delay
}                                                // End of Loop

unsigned long sendNTPpacket(IPAddress & address){// send NTP request
  memset(buff, 0, NTP_PACKET_SIZE);              //
  buff[0]=0b11100011; buff[1]=0;   buff[ 2]=6;   //
  buff[3]=0xEC;       buff[12]=49; buff[13]=0x4E;//
  buff[14]=49;        buff[15]=52;               //
  udp.beginPacket(address, 123);                 //
  udp.write(buff, NTP_PACKET_SIZE);              //
  udp.endPacket();                               //
}                                                //

void ALL(int f,String t,String h,String p){      // All Display 
  display.clearDisplay();display.setTextSize(f); //
  display.setCursor(0,0);                        //
  display.print(t);display.println(" C");        // Temp
  display.print(h);display.println(" %");        // Humi
  display.print(p);display.println(" mb");       // Press
  display.display();delay(3000);                 //
}                                                //

void THP(int f,String d,int c,String m){         // one Display
  int a = d.indexOf(".") + c;                    //
  String d_ = d.substring(0, a);                 //
  display.clearDisplay();display.setTextSize(f); //
  display.setCursor(0,0);                        //
  display.println(d_);display.println( m );      //
  display.display();delay(3000);                 // 
}                                                //

void dispset( int f, String d){                  //
  if ( f != 0 ){                                 //
   display.clearDisplay();display.setCursor(0,0);//
  }                                              //
  display.setTextSize(f);                        //
  if (d.length() > 0 ){ display.println(d);      //
  display.display();}                            //
}                                                //

void connectWiFi() {                             // WiFi connect
  if (WiFi.status() == WL_CONNECTED) {return;}   // WiFi Status check
  WiFi.begin(ssid, pass);                        //
  while(WiFi.status()!=WL_CONNECTED){delay(500);}// WiFi Status check
}                                                //

void updateThingSpeak(String data) {             // ThingSpeak
  WiFiClient client;                             //
  if (!client.connect(thingSpeakurl,80)){return;}//         
  client.print(F("GET /update?key="));           //
  client.print(thingSpeakAPIKey);                //
  client.print(F("&"));                          //
  client.print(data);                            // Field No + Sensor Data
  client.print(F(" HTTP/1.1\r\nHost: api.thingspeak.com\r\n\r\n"));
  client.println();                              //
}                                                //

void aircon_on() {                               // aircon on
  int dataSize = sizeof(acon) / sizeof(acon[0]); //
  for (int cnt = 0; cnt < dataSize; cnt++) {     // data
    unsigned long len = acon[cnt]*10;            // 0us unit:ON/OFF time
    unsigned long us = micros();                 //
    do { digitalWrite(ir, 1 - (cnt&1));          // cnt:even=ON,odd=OFF
         delayMicroseconds(8);                   // CAL GREQ 38kHz
         digitalWrite(ir, 0);                    // ON/OFF Time Adjust
         delayMicroseconds(7);                   //
    } while (long(us + len - micros()) < 0);     // Loop at TX time
  }                                              //
}                                                //

void aircon_off() {                              // aircon off
  int dataSize = sizeof(acoff)/sizeof(acoff[0]); //
  for (int cnt = 0; cnt < dataSize; cnt++) {     // data
    unsigned long len = acoff[cnt]*10;           // 0us unit:ON/OFF time
    unsigned long us = micros();                 //
    do { digitalWrite(ir, 1 - (cnt&1));          // cnt:even=ON,odd=OFF
         delayMicroseconds(8);                   // CAL GREQ 38kHz
         digitalWrite(ir, 0);                    // ON/OFF Time Adjust
         delayMicroseconds(7);                   //
    } while (long(us + len - micros()) > 0);     // Loop at TX time
  }                                              //
}                                                //


参考:
Arduinoでリモコン作成:@eiKatou Blog
赤外線リモコンの通信フォーマット
赤外線リモコンをハック!Arduinoからエアコンを起動する
純正超え!韓国製エアコン用リモコン「UMA-ACRM02」を買ってみた
なぜエアコンのリモコンは学習できないのか?


 

広告

Written by macsbug

11月 29, 2015 at 12:29 am

カテゴリー: ESP8266

赤外線LEDリモコンの制作

with 15 comments

エアコンを操作する為に 赤外線LEDでリモコンを作りました。      2015.11.29
操作は ArduinoかESP8266 で行う為に 赤外線LEDに接続する抵抗値を計算しました。


赤外線LEDのスケッチやリモコン操作については
eiKatou:Arduinoでリモコン作成を参考にしてください。@eiKatou Blog氏に感謝。
東京お気楽カメラ:WROOM02を使った赤外線リモコン その1
_ 詳細に計算されています。東京お気楽カメラ氏に感謝。:2017.09.16 追記。


結論:
赤外線LEDは OSI5LA5113A。トランジスターは 2SC2655L-Y を使用します。
トランジスターの入力抵抗は 680 Ω。:2017.09.16 変更(1.1KΩ -> 680 Ω)。
トランジスターの出力抵抗は    10 Ω。


部品:
赤外線LED  :OSI5LA5113A:IFP=1000mA   :資料秋月電子通商
トランジスター:2SC2655L-Y :コレクタ電流 2A:資料秋月電子通商
抵抗     :10Ω。680Ω。:rev. 2017.09.16(1.1K -> 680)。


抵抗値の計算:rev : 2017.09.16( 1.1K -> 675 )

R1 = (3.3-0.6)/(500/120) = 675 Ω。 R2 = (5-(1.2+0.5))/500 = 7Ω。

赤外線LED(OSI5LA113A)は、電流消費大の為 ドライバーとしてトランジスターが必要。
赤外線LEDは 500mAから1A程度流す必要があります。
Arduinoの出力電流は 最大40mA。ESP8266の出力電流は 最大10mA です。
よって ESP8266 では LEDを直接駆動できません。

赤外線LEDの条件:500mA流す事とする。電流が少ないと伝達距離が少なくなります。
100mAで15センチ程です。
トランジスターの条件:1Aか2A程度が必要。そこで2A流せる 2SC2655L-Yを選択。
入力の条件:電圧は ESP8266 3.3V 。周波数は 38KHzでトランジスタの対応可能。

計算方法:赤外線LEDとトランジスターの規格から図面に示す内容で計算しました。
◎トランジスタ入力:ベース入力  の 抵抗の計算値は 675 Ωにて 680 Ωを接続。:rev.2017.09.16
◎トランジスタ出力:LEDに接続する抵抗の計算値は    7 Ωにて 10 Ωを接続。


準備:
Arduino:
Arduinoでリモコン:Arduinoでリモコン作成
東京お気楽カメラ  :WROOM02を使った赤外線リモコン その1::2017.09.16 追記。

以上で、部屋の隅からでもエアコンをリモコン操作できました。


メモ:
計算方法はこれで良いかと思いますが 間違っていたらごめんなさい。
ALPSのリモコンは、トランジスタとLEDの所に、10 Ω が付いていました。


2016.05.25 変更:OSI5LA113A -> OSI5LA5113A
2017.09.16 変更:式は良いが 3.3V を 5V で計算していたミスが判明。
_ 2of9 氏のご指摘により誤記の原因が判明しました。
_ 2of9 さん 大変ありがとうございます。感謝致します。


 

Written by macsbug

11月 29, 2015 at 12:13 am

カテゴリー: Arduino, ESP8266

NTPcube ( ESP8266 + OLED )

with 3 comments

NTP(Network Time Protocol) サーバ から、時刻情報を取得しOLEDに表示しました。            2015.11.17



仕組み:NTPcube が 下図の NTPクライアントになります。


準備:
ESP8266 + NTPCliant  で時刻を取得し OLED に表示する
ESP8266+BME280+OLED+BOX
基本スケッチは、Ivan Grokhotkov氏に感謝。
SSIDとPassword は各自で設定の事。
ルーターの設定:ルーターにマックアドレスの設定が必要な場合は、事前にマックアドレスを調べるか
_ 電源ON時、OLEDにマックアドレスが表示されますので確認してください。(命令:WiFi.macAddress())。


感想:
NTPが何かを知りませんでしたが、ネットの時刻情報から時計が作れ小さなケースに入れると楽しいものです。
NTPは、本来PCの時計あわせに使うようですが、家の中の環境では、GPSや電波時計より時刻情報を得やすいです。
ネットにアクセスする為に、秒単位の表示は無理で分単位にしました。アクセスは 10秒ごとです。
ネットの負荷を少なくする為に、内蔵時計を使用し時刻あわせに NTP を使用した方が良いかとも思います。
内蔵時計の時刻あわせは、通信の時間やスケッチ上の時間遅れがあり、秒単位の設定は考慮が必要と思われます。


// Udp NTP Client
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <SPI.h>
#include <BME280_MOD_1022.h>
#include <Adafruit_GFX.h>
#include <ESP_Adafruit_SSD1306.h>
#include <Time.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
extern "C" {
  #include "user_interface.h"
}
char ssid[] = "xxxx";                 // your network SSID (name)
char pass[] = "xxxx";                 // your network password
unsigned int localPort = 2390;        // local port to listen for UDP packets
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48;       // NTP time stamp:first 48 bytes
byte packetBuffer[NTP_PACKET_SIZE];   // buffer:incoming and outgoing packets
WiFiUDP udp;                          // UDP:send & receive packets over UDP

void setup(){
  //Serial.begin(115200);
  //---------------------------------------------//
  Wire.begin(13, 14); delay(10);                 // SDA,SCL(GPIO_13,GPIO_14)
  display.begin(SSD1306_SWITCHCAPVCC,0x78>>1);   // I2C_ADDRESS
  display.clearDisplay();                        // all pixels off 
  display.setTextSize(1);                        // printable sizes 1 to 8
  display.setTextColor(WHITE);                   // WHITE, BLACK, INVERSE
  display.setCursor(0,0);                        // location x,y
  display.display();                             // plotted items
  //---------------------------------------------//
  display.print("Mac ");display.println(WiFi.macAddress());display.display();
  display.print("Connecting to ");display.println(ssid);display.display();
  WiFi.begin(ssid, pass); 
  while (WiFi.status() != WL_CONNECTED){
    delay(500);display.print(".");display.display();} display.println("ok");
  display.print("IP: ");display.println(WiFi.localIP());
  udp.begin(localPort);
  display.print("Local port: ");display.println(udp.localPort());
  display.display();dealy(2000);
}

void loop(){
  sendNTPpacket(timeServer);delay(1000);// send NTP packet time server & Wait
  int cb = udp.parsePacket();
  if (!cb) {display.println("no packet yet");display.display();}
  else {
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into buffer
    unsigned long highWord = word(packetBuffer[40],packetBuffer[41]);
    unsigned long lowWord  = word(packetBuffer[42],packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    const unsigned long seventyYears = 2208988800UL;   // Convert NTP time
    unsigned long epoch = secsSince1900 - seventyYears;// Unix time
    epoch = epoch + 32400;  // UTC + 9 ( 9 * 60 * 60 ) // JST
    setTime(epoch);         // Date Time set
    display.clearDisplay();display.setTextSize(2);display.setCursor(0,0);
    // Date
    display.print(year());display.print('/');
    display.print(month());display.print('/');
    display.println(day());display.display(); 
    // Time 
    display.setTextSize(4);
    if (((epoch % 86400L)/3600) < 10){display.print('0');}
    display.print((epoch % 86400L)/3600);display.print(':'); // day
    if (((epoch % 3600)/60) < 10 ){display.print('0');}
    display.println((epoch % 3600)/60);                      // minute
    //display.print(':');if ((epoch % 60) < 10 ){display.print('0');}
    //display.println(epoch % 60);                           // second
    display.display();
  }
  delay(10000); // wait 10 seconds before asking for the time again
}

unsigned long sendNTPpacket(IPAddress& address){ // send an NTP request
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  packetBuffer[0] = 0b11100011;// LI, Version, Mode
  packetBuffer[1] = 0;         // Stratum, or type of clock
  packetBuffer[2] = 6;         // Polling Interval
  packetBuffer[3] = 0xEC;      // Peer Clock Precision
  packetBuffer[12]  = 49;      // 8 bytes of zero for Root:Delay & Dispersion
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  udp.beginPacket(address, 123);//NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}

Written by macsbug

11月 17, 2015 at 7:58 am

カテゴリー: ESP8266

ESP8266+BME280+OLED+BOX

with 2 comments

ESP8266(ESP-WROOM-02等) + I2C BME280(温度、湿度、気圧センサー) + OLED              2015.11.14


温度、湿度、気圧を測る BME280センサーのデーターを ESP8266 で OLED に表示しました。
ケースのサイズは、49 x 49 x 42 mm の手のひらに乗る大きさで、なかなかいい感じになります。


表示は、温度+湿度+気圧  -> 温度 -> 湿度 -> 気圧 を繰り返す。


基本回路:


基板の準備:ESPの基板画像は省略(右の基板のソケット上に装着する)。


 

USB Chrager の出力5Vから基板中央にあるレギュレーター(NJM2845DL1-33) により 3.3V を作る。
OLEDの固定:特殊な物はPolymorphで止める。これは数分で出来るので便利。
BME280センサー:左下の4ピンに縦に接続。
プログラミング:USB接続で外付けのコネクタ経由(中央上側の4ピンコネクタ)で行う。
書き込みボタン:外付けのコネクタ経由(中央下側の3ピンコネクタ)で行う。


電源:Logitech L-LY11 Battery pack + DLG-MRD-100 USB Chrager:出力の2本(上赤黒)は5VDC。


準備:
1. ESP8266をArduino IDE で書き込める状態である事。
2. ESP-WROOM-02 等。
3. I2C BME280:ebayから購入(846円)。
4. Battery:Logitech L-LY11 Battery pack:3.7V 600mA:ロジテックの無線マウスを分解して使う。
5. USB Chrager:DLG-MRD-100:以前、千石電商で特価品のモバイル充電器を分解して使う:500円。
6. 箱:3Dプリンターにて 制作。
7. Polymorph:湯温で軟化し常温で硬化する樹脂。ebayから購入。
8. 5V to 3.3V 800mAレギュレーター:NJM2845DL1-33、1uF,10uF,47uF。
9. 他:基板、コネクター、スイッチ、等々。


スケッチ:

// ESP8266 + I2C BME280 + OLED BOX
// Using the SSD1306 Text/Graphics OLED Display module
// http://engineeringnotes.blogspot.jp/2013/07/using-ssd1306-textgraphics-display.html
#include <Wire.h>
#include <SPI.h>;
#include <BME280_MOD_1022.h>                     // BME280 Liblary
#include <Adafruit_GFX.h>                        // OLED   Liblary
#include <ESP_Adafruit_SSD1306.h>                // OLED   Liblary
#define OLED_RESET 4                             // OLED   RESET
Adafruit_SSD1306 display(OLED_RESET);            // OLED   RESET
extern "C" {
  #include "user_interface.h"
}
long t = -4.07;                                  // BME280 Temp     offset
long h = +7.84;                                  // BME280 Humidity offset
long p = +4.52;                                  // BME280 Pressure offset

void setup() {
  Serial.begin(115200);                          // Serial TRx
  Wire.begin(13, 14); delay(10);                 // SDA,SCL(GPIO_13,GPIO_14)
  //---------------------------------------------//
  display.begin(SSD1306_SWITCHCAPVCC,0x78>1);    // I2C_ADDRESS
  display.clearDisplay();                        // all pixels off 
  display.setTextSize(1);                        // printable sizes 1 to 8
  display.setTextColor(WHITE);                   // WHITE, BLACK, INVERSE
  display.setCursor(0,0);                        // location x,y
  display.display();                             // plotted items
  //---------------------------------------------//
  BME280.readCompensationParams();               // read NVM comp parameters
  BME280.writeOversamplingTemperature(os1x);     // 1x over sampling
  BME280.writeOversamplingHumidity(os1x);        // 1x over sampling
  BME280.writeOversamplingPressure(os1x);        // 1x over sampling
}

void loop() {
  BME280.writeMode(smForced); delay(50);         // chip goes back to sleep
  while (BME280.isMeasuring()){;delay(50);}      // Measurering check
  BME280.readMeasurements();                     // read out the data
  String temp=String(BME280.getTemperature()+t); // Temp
  String humi=String(BME280.getHumidity()+h);    // Humidity
  String pres=String(BME280.getPressure()+p);    // Pressure
  //---------------------------------------------//
  all( temp, humi, pres );                       // All  Display
  temp_humi_Pres( temp, 2, "    C");             // temp Display
  temp_humi_Pres( humi, 2, "    %");             // humi Display
  temp_humi_Pres( pres, 0 ,"  hpa");             // pres Display
}

void all(String temp,String humi,String pres){   // All  Display 
  display.clearDisplay();display.setTextSize(2);
  display.setCursor(0,0);
  display.print(temp);display.println(" C");
  display.print(humi);display.println(" %");
  display.println("");
  display.print(pres);display.println(" mb");
  display.display(); 
  delay(3000);
}

void temp_humi_Pres(String data,int c,String m){ // one Display
  int a = data.indexOf(".") + c;
  String data_ = data.substring(0, a);
  display.clearDisplay();display.setTextSize(4); 
  display.setCursor(0,0);
  display.println(data_);display.println( m );
  display.display(); 
  delay(3000);
}


問題点:
1. 正しい温度とは:幾つかのセンサーで温湿度計を作った物や通常の製品と比較すると誤差が大きい。
_ 製品版でも差があるので、どうしたものかという事になる。
_ 測定する場所でも差がでてくる。これでは、小数点一桁のセンサーを使用しても意味が無くなってくる。
_ 今回は乱暴かもしれないが4個の温湿度計を集めて平均値の差をオフセット値として加えた。
2. 通気:製品版を参考にセンサー用にケース後ろに通気用の穴を開けた。
3. OLEDのフォントサイズ:フォントは拡大表示ができるが奇麗さがなくなる。
_ 奇麗に出す事のでるフォントはあるが、今回は採用せず。


感想:
1. 電源不要で最も安価な温度計は、百均にある。
2. 今回は、センサーの温度、湿度、気圧 表示だけにしました。
3. データーをSingSpeakに送るには、以前の記事を参考にスケッチを加えれば動きます。
4. ESPのWiFi機能を追加すればもっと楽しい物ができますね。
5. Logitech の L-LY11 Battery pack は、角のある形が良くかなり便利でしたし容量も満足できます。
_ ラジコン用のバッテリーの場合は、形に丸みがある事や電流容量、価格が問題になってくる。
6. 完成基板が欲しい:
_ ケースも含めた完成品があると、プログラムに集中できる事とアイデアが湧いてくる。
_ ブレットボードでの試作は動作確認できてよいが、プログラム制作の集中度が低くなる訳です。
_ こうして体験すると ESP には完成品がなく電子工作する上で時間を要したり完成度が低くなる。
_ 直ぐ動く完成基板を作りたいが私にはまだその経験がありません。
7. ケースと基板:ケースに基板を固定する必要があり、設計の段階から基板を止める場所の確保が必要でした。


 

Written by macsbug

11月 14, 2015 at 1:08 am

カテゴリー: ESP8266

ESP-WROOM-02 ファームウェアアップデート

leave a comment »

ESP-WROOM-02 に スケッチを書き込むと AT コマンドが使えなくなる。    2015.11.05
ESP-WROOM-02 用のメモとして備忘録を記載しました。


AT コマンドを使えるようにするには、マックでターミナル操作が必要となります。
ターミナル操作は面倒ですが手順をまとめ動く事を確認しました。(ESP-WROOM-02で確認)
参考:ESP8266 ファームウェアアップデート(ESP-01)

書き込み装置の用意や、ファームウエアーのダウンロードはとても面倒です。
まして、ターミナル操作となると理解できないコマンドを入力する事がさらに面倒です。
そんな私も以下の要領で、なんとかできるようになりましたので参考にしてください。


準備:以下のように配線します:PROGスイッチは、ジャンパーワイヤーのほうが便利です。

環境:Mac OSX 10.8.5 Mountain Lion にて実施。

手順: ターミナルと esptool を使用した方法。

01. ESP8266 の GPIO_0 を GND にする。スイッチでなくワイヤーでジャンパーした方が楽です。
02. esp という名前のフォルダーをデスクトップに作る。
03. USBで接続したデバイス名を Arduino IDEで調べてメモる。例:cu.usbserial-ABC
04. esptool-master.zip をダウンロード。
_  https://github.com/themadinventor/esptool :esptool.py を入手する。
05. 解凍した esptool-master フォルダーの中味を、espフォルダーに入れる。
06. esp_iot_sdk_v1.4.0_15_09_08.zip をダウンロード。
_  http://http://bbs.espressif.com/viewtopic.php?f=46&t=1124 の下にある。
07. ダウンロードしたファイル名は、esp_iot_sdk_v1-2。
08. esp_iot_sdk_v1-2 を、esp_iot_sdk_v1_2 に変更。
09. esp_iot_sdk_v1_2 > esp_iot_sdk_v1.4.0 > bin > boot_v1.4(b1).bin を、boot_v1.4b1.bin に変更。
10. esp_iot_sdk_v1_2 のフォルダーを、espフォルダーに入れる。
11. 以下、ターミナル入力
12. cd desktop/esp/
13. sudo python setup.py install
14. cd esp_iot_sdk_v1-2/esp_iot_sdk_v1.4.0/bin/
15. ESP8266 のRST端子をGNDにしてOPENする。(RESET スイッチをプッシュし離す )
16. 以下の文に、メモしたUSBデバイス名を入れてターミナル入力する。
17. esptool.py -p /dev/cu.usbserial-ABC write_flash -ff 40m -fm qio -fs 32m 0x00000 boot_v1.2.bin 0xfc000 esp_init_data_default.bin 0xfe000 blank.bin 0x01000 at/1024+1024/user1.2048.new.5.bin
_  esptool ,,, bin まで連続した文字です。
18. Connecting…
_   Erasing flash…
_   Wrote 2048 bytes at 0x00000000 in 0.2 seconds (73.3 kbit/s)…
_   Erasing flash…
_   Wrote 1024 bytes at 0x000fc000 in 0.1 seconds (73.2 kbit/s)…
_   Erasing flash…
_   Wrote 4096 bytes at 0x000fe000 in 0.4 seconds (78.9 kbit/s)…
_   Erasing flash…
_   Wrote 279552 bytes at 0x00001000 in 30.5 seconds (73.3 kbit/s)…
_   Leaving…
_      を表示して終了。
19. ESP8266 の GPIO_0 を OPEN にする。ジャンパーワイヤーを外す。
20. ESP8266 のRST端子をGNDにしてOPENする。(RESET スイッチをプッシュし離す )
21. ATコマンドで調べる。


メモ:ファイル名に – (ダッシュ)を含む場合 エラーが起きます。その為 _ (アンダーライン)に変更。


 

Written by macsbug

11月 5, 2015 at 12:50 am

カテゴリー: ESP8266

ESP8266 WiFi Scan のケースを作る

leave a comment »

ESP8266 による WiFi Scan を ケースにおさめました。               2015.11.02


WiFi Scan は、周囲の WiFi SSID を繰り返し表示します。

38mm x 38mm x 38mm のサイズで、見やすくする為に台も作りました。




構成:
ESP8266 と OLEDデイスプレー と 3端子レギュレーター 。電源はUSBを使用。
ディスプレーは、0.96インチ OLED 128×64 を使用。
USB 5V 80mA 程度。


スケッチ:
// SSID and RSSI for each network found
// WiFi.SSID(i);
// WiFi.RSSI(i); 
// WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*"; 
#include "ESP8266WiFi.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <ESP_Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup() {
  Serial.begin(115200);
  Wire.begin(0,2);           // SDA(GPIO_0), SCL(GPIO_2)
  display.begin(SSD1306_SWITCHCAPVCC, 0x78>>1);
  display.clearDisplay();    // Clear the buffer. 
  display.setTextSize(1);    // font size 1 ( minnimum )
  display.setTextColor(WHITE);
  display.clearDisplay();display.println("Connecting to");display.display();
  delay(100);Serial.println("Setup done");display.display();
}

void loop() {
  display.clearDisplay();
  display.setCursor(0,0);
  int n = WiFi.scanNetworks(); // number of networks found
  if (n == 0){display.println("no networks found");}
  else{
    int y = 9;
    for (int i = 0; i < n; ++i ){
      y = y - 1;
      if ( y == 0){ delay(3000);
        display.clearDisplay();display.setCursor(0,0); y = 9;
      }
      display.println(WiFi.SSID(i));display.display(); // SSID
      delay(10);
    }
  }
  delay(10000); // Wait a bit before scanning again
}

メモ:
このサンプルは、ESP や OLED のテストに使用できます。
ESPは、受信のみのテストができます。
これは、ルーターを介さない為に ルーターの設定や接続不良、誤動作はありません。
OLEDは電源投入時に "Connecting to" を表示するか、SSIDを受信すれば、SSIDが表示
されますから OLED のテストもできる訳です。


	

Written by macsbug

11月 2, 2015 at 8:10 am

カテゴリー: ESP8266

ESP8266WiFi のサンプルを試す:WiFiScan

leave a comment »

ESP8266 のサンプルが動く事を確かめる。                            2015.11.02
その4:WiFiScan


SSID, RSSI, WiFi encryption Type が表示されている。


準備:
ハード :ESP-WROOM-02 及び 書き込み環境が用意されている事
開発環境:Arduino IDE 1.6.5:Tools -> Board に Generic ESP8266 Module の設定及び選択されている事。
スケッチ:Sandeep Mistry氏の sandeepmistry から esp8266-Arduino をダウンロードする。
_ 必要の無い物もある為、ここでは、esp8266 というフォルダーを作り Liblary をまとめる。
_ 以下の Liblary(ESP8266WiFi等々) の中味を esp8266 フォルダーに入れ Arduino のライブラリ−に入れる。
_ esp8266-Arduino > esp8266com/esp8266 > libraries > ESP8266WiFi等々


スケッチを選択する:
Liblary > esp8266 > ESP8266WiFi > WiFiScan
スケッチの変更:なし。


以上、これだけで、動きました。

Written by macsbug

11月 2, 2015 at 8:05 am

カテゴリー: ESP8266