Daily Archives: October 9, 2020

TinyWebDB API IoT Test App

Published by:

IoT test アプリと連携を試み

システム構成

IoTデバイスから、TinyWebDB API を通して、クラウドに温度と気圧のデータが送信、そしてLEDのOn/Offデータを受信する。

このアプリは、クラウドの温度と気圧のデータが受信、そしてLEDのOn/Offデータを送信する機能を持つ。

実験方法

モバイルからTinyWebDB APIに接続する手順:

  1. App Inventor でTinyWebDBを利用するアプリを作成
  2. TinyWebDBのURLは、http://tinydb.mlと設定
  3. アプリは、TinyWebDBクラウドの温度、気圧のデータ読み込みを確認
  4. On/Offボタン操作で、TinyWebDBクラウドに書き込みを確認
  5. On/Offボタン操作で、IoT-Cloud-Mobile実験セットのLEDの点灯、消灯を確認

 

IoT test Appを作る

MIT App Inventor で IoT test Appができたので、紹介する。

デザイナー画面

デザイナー画面では、LEDのOn/Offボタンと、温度と気圧のデータが表示する領域がある。

プログラムのブロック

プログラムのブロックは次のようになる。

実機画面

このアプリにより、IoTデバイスの温度、気圧のデータ表示ができ、そしてIoTデバイスに備えたLEDのOn/Offもできた。

ESP9266 Send IoT data to TinyWebDB

Published by:

IoTデータの送受信実験

  1. IoT-Cloud-Mobile実験セットを用意
  2. Arduinoを利用して、実験スケッチを書き込み
  3. WiFi接続の設定
  4. OLED画面から、装置のIP, 現在の温度、気圧を確認
  5. 温度、気圧のデータは、TinyWebDB クラウドに記録することを確認

 

 

手順

  1. WeMos (1) Blink
  2. WeMos (7) I2C OLED SSD1306 (Adafruit)
  3. WeMos (b3) BMP280 I2C
  4. WeMos (c2) WiFiManager
  5. WeMos (d2) Home Automation

TinyWebDB API@RPi

Published by:

実験用だけなら、現在次のサーバを利用してください。

http://tinydb.ml/

運用して、データ収集、蓄積を考えるなら、独自のTinyWebDBクラウドの構築する方がいいでしょう。

ちなみに、次は天気センサーの記録専用サーバです。

http://weather.uc4.net/

VPSサーバでTinyWebDBサービス

簡単なテキストベースのTinyWebDBサービスを構築

  1. LinuxサーバでApache virtual hostを作る
  2.  .htaccessを許可 (set AllowOverride to All)
  3. 下記のGithub ファイルをvirture host ルートにclone.

Raspberry PiでTinyWebDBサービス

Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピューター。イギリスのラズベリーパイ財団によって開発されている。学校で基本的なコンピュータ科学の教育を促進することを意図している。

図 4.5 Raspberry Pi

Raspberry Piセットアップ

Raspberry PiはDebianというOSを利用する。予めシステム入れたメディアを購入する、またはOSのファイルをダウンロードし、メディアにセットアップする。

LAMP(ランプ)とは、OSであるLinux、WebサーバであるApache HTTP Server、データベースであるMySQL、スクリプト言語であるPerl、PHP、Pythonを総称した頭文字から成る造語である。動的なウェブコンテンツを含むウェブサイトの構築に適した、オープンソースのソフトウェア群である。

それからRaspberry PiにLAMP環境構築してください。

Web サービスの構築

簡単なテキストベースのTinyWebDBサービスを構築

  1. Raspberry PiサーバでApache起動を確認する
  2.  .htaccessを許可 (set AllowOverride to All)
  3. 下記のGithub ファイルを html ルートにclone.

WeMos (d2) Home Automation

Published by:

TinyWebDB-APIを利用した、Home Automationの例。

ハードウェア

“IoT-Cloud-Mobile Study Kit”を利用

TinyWebDBサーバ

今まで、いくつ実験サーバは建てたが、現在生きてるサーバは、次のサーバになります。

  1. http://tinydb.ml/
  2. http://tinywebdb.cf

参考に今まで実験に使ったのサーバリスト:

  1. http://tinydb.ml/api/
  2. http://tinydb.work/api/
  3. http://tinywebdb.cf/api/

データ送信

下記のは操作中、数分起き温度、気圧センサーのデータをTinyWebDB-APIテストサーバ(http://tinydb.ml/)へ送信する。

送信したデータは、http://tinydb.ml/で確認できる。

データ受信

スマートフォンからLED On/Off の指令は受信すると、ESP8266内蔵LEDは点/滅可能になった。

 

ソースコード

// Sample Arduino Json Web Client
// Downloads and parse http://jsonplaceholder.typicode.com/users/1
//
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://bblanchon.github.io/ArduinoJson/
// If you like this project, please add a star!

#include <ArduinoJson.h>
#include <Arduino.h>

#include <Adafruit_BMP280.h>
#define BMP_SCK 13
#define BMP_MISO 12
#define BMP_MOSI 11 
#define BMP_CS 10

Adafruit_BMP280 bmp; // I2C
//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI
//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO,  BMP_SCK);

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define OLED_RESET 0  // GPIO0
Adafruit_SSD1306 OLED(OLED_RESET);

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

#define USE_SERIAL Serial

WiFiClient client;

const char* resource = "http://tinydb.ml/api/"; // http resource
const unsigned long BAUD_RATE = 9600;      // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 512;       // max size of the HTTP response

#include "WiFiManager.h"          //https://github.com/tzapu/WiFiManager

void configModeCallback (WiFiManager *myWiFiManager) {
  OLED.println("Entered config mode");
  OLED.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  OLED.println(myWiFiManager->getConfigPortalSSID());
  OLED.display(); //output 'display buffer' to screen  
}

HTTPClient http;

void setup() {
    OLED.begin();
    OLED.clearDisplay();
   
    //Add stuff into the 'display buffer'
    OLED.setTextWrap(false);
    OLED.setTextSize(1);
    OLED.setTextColor(WHITE);
    OLED.setCursor(0,0);
    delay(10);

    USE_SERIAL.begin(115200);
   // USE_SERIAL.setDebugOutput(true);

    USE_SERIAL.println();
    USE_SERIAL.println();
    USE_SERIAL.println();

    OLED.println("wifiManager autoConnect...");
    OLED.display(); //output 'display buffer' to screen  

    //WiFiManager
    //Local intialization. Once its business is done, there is no need to keep it around
    WiFiManager wifiManager;
    //reset settings - for testing
    //wifiManager.resetSettings();
  
    //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
    wifiManager.setAPCallback(configModeCallback);
  
    //fetches ssid and pass and tries to connect
    //if it does not connect it starts an access point with the specified name
    //here  "AutoConnectAP"
    //and goes into a blocking loop awaiting configuration
    if(!wifiManager.autoConnect()) {
      Serial.println("failed to connect and hit timeout");
      //reset and try again, or maybe put it to deep sleep
      ESP.reset();
      delay(1000);
    } 
  
    //if you get here you have connected to the WiFi
    Serial.println("connected...yeey :)");

    if (!bmp.begin(0x76)) 
    {
      OLED.println("Could not find BMP280");
      OLED.display(); //output 'display buffer' to screen  
      while (1) {}
    }
}

void OLED_show()
{

  OLED.clearDisplay();
  OLED.setCursor(0,0);
  // Print the IP address
  OLED.print("http://");
  OLED.print(WiFi.localIP());
  OLED.println("/");
  OLED.setCursor(0,8);
  OLED.print("Temp = ");
  OLED.print(bmp.readTemperature());
  OLED.println(" Celsius");
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  OLED.setCursor(0,16);
  OLED.print("Pres = ");
  OLED.print(bmp.readPressure());
  OLED.println(" Pascal ");

  OLED.display(); //output 'display buffer' to screen  
}


void loop() {
    OLED_show();
    get_TinyWebDB("Led1");
    delay(10000);
    sensor_TinyWebDB();
    delay(10000);
}

void sensor_TinyWebDB() {    
    int httpCode;
    char  tag[32];
    char  value[128];

    // read values from the sensor
    float pressure = bmp.readPressure();
    float temperature = bmp.readTemperature();

    const size_t bufferSize = JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(3);
    DynamicJsonBuffer jsonBuffer(bufferSize);
    
    JsonObject& root = jsonBuffer.createObject();
    root["sensor"] = "bmp280";
    root["temperature"] = String(temperature);
    root["pressure_hpa"] = String(pressure);
    root.printTo(value);

    USE_SERIAL.printf("[TinyWebDB] %sn", value);
    USE_SERIAL.printf("ESP8266 Chip id = %08Xn", ESP.getChipId());
    sprintf(tag, "esp8266-%06x", ESP.getChipId());
    httpCode = TinyWebDBStoreValue(tag, value);
    // httpCode will be negative on error
    if(httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        USE_SERIAL.printf("[HTTP] POST... code: %dn", httpCode);

        if(httpCode == HTTP_CODE_OK) {
            TinyWebDBValueStored();
        }
    } else {
        USE_SERIAL.printf("[HTTP] GET... failed, error: %sn", http.errorToString(httpCode).c_str());
        TinyWebDBWebServiceError(http.errorToString(httpCode).c_str());
    }

    http.end();

    delay(10000);
}

void get_TinyWebDB(const char* tag0) {    
    int httpCode;
    char  tag[32];
    char  value[128];

    httpCode = TinyWebDBGetValue(tag0);

    // httpCode will be negative on error
    if(httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        USE_SERIAL.printf("[HTTP] GET... code: %dn", httpCode);

        if(httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            const char * msg = payload.c_str();
            USE_SERIAL.println(payload);
            if (TinyWebDBreadReponseContent(tag, value, msg)){
                TinyWebDBGotValue(tag, value);
            }
        }
    } else {
        USE_SERIAL.printf("[HTTP] POST... failed, error: %sn", http.errorToString(httpCode).c_str());
        TinyWebDBWebServiceError(http.errorToString(httpCode).c_str());
    }

    http.end();

    delay(10000);
}

int TinyWebDBWebServiceError(const char* message)
{
}

// ----------------------------------------------------------------------------------------
// Wp TinyWebDB API
// Action        URL                      Post Parameters  Response
// Get Value     {ServiceURL}/getvalue    tag              JSON: ["VALUE","{tag}", {value}]
// ----------------------------------------------------------------------------------------
int TinyWebDBGetValue(const char* tag)
{
    char url[64];

    sprintf(url, "%s%s?tag=%s", resource, "getvalue/", tag);

    USE_SERIAL.printf("[HTTP] %sn", url);
    // configure targed server and url
    http.begin(url);
    
    USE_SERIAL.print("[HTTP] GET...n");
    // start connection and send HTTP header
    int httpCode = http.GET();

    return httpCode;
}

int TinyWebDBGotValue(const char* tag, const char* value)
{
    USE_SERIAL.printf("[TinyWebDB] %sn", tag);
    USE_SERIAL.printf("[TinyWebDB] %sn", value);

    OLED.printf("[TinyWebDB] %s:%sn", tag, value);
    OLED.display(); //output 'display buffer' to screen  
    
    return 0;   
}

// ----------------------------------------------------------------------------------------
// Wp TinyWebDB API
// Action        URL                      Post Parameters  Response
// Store A Value {ServiceURL}/storeavalue tag,value        JSON: ["STORED", "{tag}", {value}]
// ----------------------------------------------------------------------------------------
int TinyWebDBStoreValue(const char* tag, const char* value)
{
    char url[64];
  
    sprintf(url, "%s%s", resource, "storeavalue");
    USE_SERIAL.printf("[HTTP] %sn", url);

    // POST パラメータ作る
    char params[128];
    sprintf(params, "tag=%s&value=%s", tag, value);
    USE_SERIAL.printf("[HTTP] POST %sn", params);

    // configure targed server and url
    http.begin(url);

    // start connection and send HTTP header
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    int httpCode = http.POST(params);
    String payload = http.getString();                  //Get the response payload
    Serial.println(payload);    //Print request response payload

    http.end();
    return httpCode;
}

int TinyWebDBValueStored()
{
  
    return 0;   
}


// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
// [
//   "VALUE",
//   "LED1",
//   "on",
// ]
bool TinyWebDBreadReponseContent(char* tag, char* value, const char* payload) {
  // Compute optimal size of the JSON buffer according to what we need to parse.
  // See https://bblanchon.github.io/ArduinoJson/assistant/
  const size_t BUFFER_SIZE =
      JSON_OBJECT_SIZE(3)    // the root object has 3 elements
      + MAX_CONTENT_SIZE;    // additional space for strings

  // Allocate a temporary memory pool
  DynamicJsonBuffer jsonBuffer(BUFFER_SIZE);

  // JsonObject& root = jsonBuffer.parseObject(payload);
  JsonArray& root = jsonBuffer.parseArray(payload);
  JsonArray& root_ = root;

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  // Here were copy the strings we're interested in
  strcpy(tag, root_[1]);   // "led1"
  strcpy(value, root_[2]); // "on"

  return true;
}


// Pause for a 1 minute
void wait() {
  Serial.println("Wait 60 seconds");
  delay(60000);
}

 

 

参考:

  • TinyWebDB-API : https://wordpress.org/plugins/tinywebdb-api/
  • https://techtutorialsx.com/2016/07/21/esp8266-post-requests/

WeMos (c2) WiFiManager

Published by:

WeMos のWiFiが、前回のようにSSIDとPASSWORDをコードに書き込む方法の他に、オンライン変更できるような方法もある。

WiFiManager というライブラリを使うと簡単にできる

https://github.com/tzapu/WiFiManager

このソースを参考に試してみる。

まず、ライブラリマネージャーから、WiFiManagerを検索して、インストールする。

ライブラリを使える状態にすると,下記のサンプルで、接続するだけで上のユースケースが満たされて大変便利だ…。標準でWebUIもついてる。

#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino

//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include "WiFiManager.h"          //https://github.com/tzapu/WiFiManager

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  
  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;
  //reset settings - for testing
  //wifiManager.resetSettings();

  //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
  wifiManager.setAPCallback(configModeCallback);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "AutoConnectAP"
  //and goes into a blocking loop awaiting configuration
  if(!wifiManager.autoConnect()) {
    Serial.println("failed to connect and hit timeout");
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(1000);
  } 

  //if you get here you have connected to the WiFi
  Serial.println("connected...yeey :)");
 
}

void loop() {
  // put your main code here, to run repeatedly:

}

 

WiFiManager 動作の流れ

  1. 保存されている認証情報があれば、その情報を使ってAPに接続する
  2. 保存されている情報がないか、あっても接続できなければ、Wi-Fiをスキャンして接続候補となるAPを探し、ESP8266自身がアクセスポイントモードになり、認証情報の入力を待つ
  3. ユーザーがESP8266のAPに接続すると、ESP8266自身が立ち上げたWebサーバーに接続され、表示されているAP候補の中から接続したいAPを選択し、そのパスワードを入力する。
  4. ESP8266は指定されたSSIDとパスワードでAPに接続する

ESP8266アクセスポイントモード

保存されている情報がないか、あっても接続できなければ、Wi-Fiをスキャンして接続候補となるAPを探し、ESP8266自身がアクセスポイントモードになり、認証情報の入力を待つ。

まずスマートフォンの「設定」の中の「Wi-Fi」を開く。自宅のWi-Fiルーターの他に”AutoConnectAP”というAPが見つかります。これがESP8266なので、これを選択。

image

接続したいAPを選択

ユーザーがESP8266のAPに接続すると、ESP8266自身が立ち上げたWebサーバーに接続される。

自動的にブラウザーが立ち上がる場合もありますし、そうでない場合はブラウザーを起動します。するとESP8266のWebサーバーに接続され、次の画面が表示されます。

image

ここで「Configure WiFi」をタップすると、近くにあるWi-Fi APのリストが表示されます。表示されているAP候補の中から接続したいAPを選択し、そのパスワードを入力。するとESP8266は指定されたSSIDとパスワードでAPに接続する。

WeMos (b3) BMP280 I2C

Published by:

ライブラリの追加

“Adafruit Unified Sensor”ライブラリの追加

スクリーンショット 2017-09-04 15.24.15

センサーをライブラリ追加

BMP280センサーを利用する

ライブラリからBMP280を検索して、追加してください

測定プログラム

/***************************************************************************
  This is a library for the BMP280 humidity, temperature & pressure sensor
  Designed specifically to work with the Adafruit BMEP280 Breakout 
  ----> http://www.adafruit.com/products/2651
  These sensors use I2C or SPI to communicate, 2 or 4 pins are required 
  to interface.
  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
 ***************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#define BMP_SCK 13
#define BMP_MISO 12
#define BMP_MOSI 11 
#define BMP_CS 10
Adafruit_BMP280 bmp; // I2C
//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI
//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO,  BMP_SCK);
void setup() {
  Serial.begin(9600);
  Serial.println(F("BMP280 test"));
  
  if (!bmp.begin(0x76)) {  
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    while (1);
  }
}
void loop() {
    Serial.print(F("Temperature = "));
    Serial.print(bmp.readTemperature());
    Serial.println(" *C");
    
    Serial.print(F("Pressure = "));
    Serial.print(bmp.readPressure());
    Serial.println(" Pa");
    Serial.print(F("Approx altitude = "));
    Serial.print(bmp.readAltitude(1013.25)); // this should be adjusted to your local forcase
    Serial.println(" m");
    
    Serial.println();
    delay(2000);
}

 

WeMos (7) I2C OLED SSD1306 (Adafruit)

Published by:

仕様

[0.96 インチ 4Pin IIC I2C ブルー OLED ディスプレイ モジュール Arduino対応]を使ってみる。

主な仕様は次のようになっています。

  • I2C通信
  • ディスプレイコントローラ: SSD1306
  • 解像度: 128×64
  • 電圧: 3.3V-5V

ライブラリ

次の2つライブラリが必要

  1. Adafruit_GFX
  2. Adafruit_SSD1306

こちらを参考にして、すんなりできた。下記の2つライブラリもSSD1306対応だ。

  • ThingPulseのライブラリ(SSD1306, SH1106対応)
  • U8g2ライブラリ(多数OLED対応)

結線

I2Cの場合、デフォルトはSDA、SCLはD1、D2。

サンプルコード

デフォルトはSDA、SCLはD1、D2。変更する場合、 Wire.begin(4,5); // OLED:SDA,SCL 行を変更して対応できるらしい。

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define OLED_RESET 0  // GPIO0
Adafruit_SSD1306 OLED(OLED_RESET);
 
void setup()   {
  //  Wire.begin(4,5);              // OLED:SDA,SCL
  OLED.begin();
  OLED.clearDisplay();
 
  //Add stuff into the 'display buffer'
  OLED.setTextWrap(false);
  OLED.setTextSize(1);
  OLED.setTextColor(WHITE);
  OLED.setCursor(0,0);
  OLED.println("automatedhome.party");
 
  OLED.display(); //output 'display buffer' to screen  
  OLED.startscrollleft(0x00, 0x0F); //make display scroll 
} 
 
void loop() {
}

 

これて、i2c 複数繋いて、いい感じ。

参考

WeMos (1) Blink

Published by:

Setup Arduino IDE

Arduino IDEがまたインストールしてないの場合、つかうPCにより、下記の何れを参考にArduino IDEのインストールする。

AddOn

Arduino-IDEを使ってWeMosにスケッチを書き込むには、こ ち らを参考にESP8266用のAddOnを追加する必要がある。

  1.  [Arduino]-[環境設定]に、[ボードマネージャーURL]を追加
    http://arduino.esp8266.com/stable/package_esp8266com_index.json
  2. ボードマネージャーに、ESP8266を検索して追加

インストールは、結構大量のファイルをダウンロードするので、ココは時間が掛かる。

Blink

動作確認のため、まずLちか(Blink)をする。

ボードから、WeMosには「D1 Mini & D1 R2」を選択する。

通信ポートは、デバイスマネージャーから見えた、CH340に割り当てた通信ポート(COM3など)も設定して下さい。

「wemos windows config」の画像検索結果

MacOSの場合、次のように設定する。

スクリーンショット 2016-12-06 21.48.39.png

(LEDはGPIO 5 に接続)の場合のスケッチ。

WeMosの内蔵LEDを利用する場合、プログラムは次のように

 

#define ESP8266_LED BUILTIN_LED


void setup()
{
    pinMode(ESP8266_LED, OUTPUT);
}


void loop()
{
    digitalWrite(ESP8266_LED, HIGH);
    delay(500);
    digitalWrite(ESP8266_LED, LOW);
    delay(500);

}

 

参考

  1. http://www.esp8266learning.com/
  2. https://www.baldengineer.com/esp8266-5-reasons-to-use-one.html