All posts by chen

WeMos (c10) Web Clock

TM1637 7段4桁LED表示はできたけど、もっと何かWeb関係のものができないかと考えていて、時刻の表示くらいできると思って、やってみた。

WeMos (5) TM1637 7段4桁LED表示

WiFiManagerを利用してWiFiに接続。

結線ができるだけ省けると考えて、GPIOのPinから給電を試してみた。

プログラムはこれ、D4の隣はGNDだから、D4をVCCとして利用する様にプログラミングする。

#include <TM1637Display.h>
#include <time.h>
#include "WiFiManager.h"  
 
const int CLK = D2; //Set the CLK pin connection to the display
const int DIO = D3; //Set the DIO pin connection to the display
const int VCC = D4; //Set the VCC pin connection to the display
 
int numCounter = 0;
int numTime = 0;
String time_value;
 
TM1637Display display(CLK, DIO); //set up the 4-Digit Display.
 
void setup()
{
  Serial.begin(115200);
  Serial.println("Hello!");

  WiFiManager wifiManager;
  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);
  } 

  configTime(0 * 3600, 0, "pool.ntp.org", "time.nist.gov");

  pinMode(VCC, OUTPUT);
  digitalWrite(VCC, HIGH);
  display.setBrightness(0x04); //set the diplay to 0..7 brightness
}
 
 
void loop()
{
  for(numCounter = 0; numCounter < 1000; numCounter++) //Iterate numCounter
  {
    time_t now = time(nullptr);
    String time = String(ctime(&now));
    Serial.println("time:" + time);

    time_t utc, local;
    struct tm *tm_now;
    utc = now;
    local = utc + 9 *60 * 60;   // Tokyo time
    tm_now = localtime(&local);
    numTime = tm_now->tm_hour * 100 + tm_now->tm_min;
    Serial.printf("numTime: %d  ¥n", numTime);

    display.showNumberDecEx(numTime, 0x40); //Display the numCounter value;
    delay(500);
    display.showNumberDecEx(numTime, 0); //Display the numCounter value;
    delay(500);
  }
}

実動する画面:

デスクトップPCの肩に乗せた様子。

 

WeMos (c9) Web LED Matrix

最初はプレゼントタイマーを作るつもり。

しかし、TinyebDBの文字列を表示する方がはるかも簡単、汎用性もいい。

できたものはこれ:

電源が繋いたら、WiFiを自動で接続、それからTinyWebDBから文字列を取得と表示する。

これならプレゼントタイマーだけじゃなく、お知らせ、顔認証して名前で挨拶とかにも活用できそう。

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <time.h>

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

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

HTTPClient http;

int pinCS = D4; // Attach CS to this pin, DIN to MOSI and CLK to SCK (cf http://arduino.cc/en/Reference/SPI )
int numberOfHorizontalDisplays = 4;
int numberOfVerticalDisplays   = 1;
char time_value[20];

// LED Matrix Pin -> ESP8266 Pin
// Vcc            -> 3v  (3V on NodeMCU 3V3 on WEMOS)
// Gnd            -> Gnd (G on NodeMCU)
// DIN            -> D7  (Same Pin for WEMOS)
// CS             -> D4  (Same Pin for WEMOS)
// CLK            -> D5  (Same Pin for WEMOS)

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

int wait = 70; // In milliseconds

int spacer = 1;
int width  = 5 + spacer; // The font width is 5 pixels

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

void setup() {
  configTime(0 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  matrix.setIntensity(10); // Use a value between 0 and 15 for brightness
  matrix.setRotation(0, 1);    // The first display is position upside down
  matrix.setRotation(1, 1);    // The first display is position upside down
  matrix.setRotation(2, 1);    // The first display is position upside down
  matrix.setRotation(3, 1);    // The first display is position upside down

  display_message("wifiManager autoConnect...");

  //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() {
  matrix.fillScreen(LOW);
  get_TinyWebDB("presentationtimer");
  delay(1000);
}

void display_message(String message) {
  if (message.length() > 5) scrool_message(message);
  else {
    for ( int i = 0 ; i < message.length(); i++ ) {
      matrix.drawChar(2 + i * width, 0, message[i], HIGH, LOW, 1); // 
    }
    matrix.write(); // Send bitmap to display
  }
}

void scrool_message(String message) {
  for ( int i = 0 ; i < width * message.length() + matrix.width() - spacer; i++ ) {
    //matrix.fillScreen(LOW);
    int letter = i / width;
    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2; // center the text vertically
    while ( x + width - spacer >= 0 && letter >= 0 ) {
      if ( letter < message.length() ) {
        matrix.drawChar(x, y, message[letter], HIGH, LOW, 1); // HIGH LOW means foreground ON, background off, reverse to invert the image
      }
      letter--;
      x -= width;
    }
    matrix.write(); // Send bitmap to display
    delay(wait / 2);
  }
}


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

    httpCode = TinyWebDBGetValue(tag);

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

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

    http.end();

    delay(1000);
}

// 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;
}

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);

    Serial.printf("[HTTP] %s\n", url);
    // configure targed server and url
    http.begin(url);
    
    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)
{
    Serial.printf("[TinyWebDB] %s\n", tag);
    Serial.printf("[TinyWebDB] %s\n", value);

    display_message(value);
    delay(1000);
    display_message(value);

    
    return 0;   
}

 

TinyWebDBに文字列を用意方法はいくつもある。

  1. HTMLフォームで送信
  2. App Inventor で簡単なアプリ開発
  3. cURLで送信
  4. TinyWebDBサイトを直接いじる。
<h1>TinyWebDB test program</h1>

<form action="http://tinydb.ml/api/storeavalue" method="post">
  <div>tag: <input type="text" name="tag" value="presentationtimer"></div>
  <div>value: <input type="text" name="value" value="12:13"></div>
  <input type="submit" value="submit">
  <input type="reset" value="reset">
</form>

 

 

Raspberry Pi (12) OLED status

Raspberry Pi ZeroにOLED をつけて、statusを表示する。

Raspberry Pi Zeroは、ネットワークi/fがないため、入手して大分時間がたちまして、棚上げ状態が続く。

USB WiFiを追加し、さらにOLEDでipアドレスなどのstatusが表示できれば、使い道が増えると考えた。

試行錯誤の末、下記のものができた。

  1. オスのUSB追加で、PCに直挿入
    (2は共存できないため、不要!)
  2. USB WiFiでネットワークに接続
  3. シリアル接続ための端子を用意
  4. OLEDでstatusの表示
  5. BMP280で環境温度と気圧を収集

開発環境構築

まず、オスのUSB追加で、PCに直挿入できるように。

PCに直挿入、sshで操作らくらくと調子がいいだけと、

しかしここで、MicroUSBにWiFiドングリをさして見たら、認識しない!共存できないと発見した。

仕方なくシリアル接続ための端子を追加した。

OLEDでstatusの表示

(TBD)

BMP280で環境温度と気圧を収集

(TBD)

Webduino (5) Smart+DHT+OLED

Webduino Cloud Platformは、スケッチ保存できるクラウド環境。

(それまで、作ったスケッチは、保存できない!)

開始使用:https://cloud.webduino.io

Gmailのアカウントで簡単にログイン可能。

早速公開しているのスケッチ(Public Files から検索)を試す。意外に簡単。

Smart+OLED(圖片)

まずOLEDを増設、スケッチの通り結線しただけで表示ができた。

OLEDの接続と表示。

Smart+DHT+OLED

さらにDHT11を追加し、スケッチの通り結線しただけ、すごく気楽にできた。

DHT11を接続して、温度と湿度も簡単に表示できた。

Webduino (3) RGB LED

Webduino Smartに接続

Webduino Smartに接続方法は2つある

WiFi接続

WiFi接続はデバイスIDを利用して接続する。

この場合はWebduino Blockly ( https://blockly.webduino.io )を開いてプログラミングする。

WebSocket接続

WebSocket接続は、デバイスのローカルIPで接続する。

この場合、http://blockly.webduino.io/ を開いてプログラミングする。

ボタンでRGB LED点灯

Webduino Smartには、RGB LED内蔵なので、まず点灯してみる。

http://blockly.webduino.io/ を開いて、下記の通り、プログラミングする。

右上の “Run Blocks”をクリックして、Web Demo エリアのボタン1..5をクリックすると、対応色が点灯する。

Webduino (2) Update Firmware

ブラウザからデバイスにアクセスする場合、画面の左下に、Firmwareのバージョンが表示され(Ver 3.0.07)

セットアップが終わり、ファームウェアのアップデートを行うと勧められて、しかしどうしてもうまくいかないて、二日悩み中。

英語と中国語のtutorialsは、ここでマイクロスイッチを押し続け、ファームウェアのアップデートが自動的に行う。

  • https://webduino.io/en/tutorials/smart-02-setup.html
  • https://tutorials.webduino.io/zh-tw/docs/basic/board/smart-setup.html

しかし、いくら押し続けでも、LEDの反応がない、だがなぜかファームウェアのアップデートできない。ファームウェアのアップデートため、デバイスIDが取得できない。そして、Webduinoクラウドにも繋げられない。

悩んだ末、たまたまtutorialsのyoutubuを見てわかった。電源を再投入して、赤いLED点滅してる間に、マイクロスイッチを押し続ける

これてうまく行った!緑LED点灯など、しばらくして更新終了(無論更新中電源OFF駄目)、今度ブラウザからデバイスにアクセスする場合、デバイスIDが表示され、画面の左下に、更新後のFirmwareのバージョンが表示された。

Ver 3.1.4_0802

次にWebブラウザを使ったプログラミングを行う。

 

Webduino (1) Setup

About Webduino Smart

Webduino Smartとは、Web + Arduinoの意味合いをもち、ブラウザプログラミングができるESP8266モジュール。

https://webduino.io/

外形はESP8266でできたWemosと似ている、ただ基板の裏面は3色LED」と「明度センサー」が付いている。

Webduino Smart Wi-Fi Setup

このリンク先Webduino Smart Wi-Fi Setupを参考しながら進み。

まずはmicroUSBケーブルをさして電源を入れる。青LEDが点灯し、また裏面の3色LEDは赤点灯する。

この状態で、Webduino SmartはAPモードになる。

スマホなどからWiFi APを検索すると「Smart」というAPがいるので、そこに接続する。接続パスワードは「12345678」。

接続したらブラウザから「http://192.168.4.1」にアクセス。WiFi SSID/WiFI PWDは、自宅などのWiFI APを指定。また、Device IDは識別できるようなものを指定。「SUBMIT」ボタンをクリックし、変更を反映したら、電源を抜く。

電源を入れ直すと、裏面の3色LEDは、赤点灯したあと、一瞬緑点灯し、消灯する。

この状態で、自宅WiFI APに接続された状態となる。

Webdiunoに割り当てられたIPアドレスを確認するには、スマホなどでWiFi AP検索する。

上記の様に「Smart_<IPアドレス>」という形でIPアドレスが表示されるので確認する。

まずは動作確認として、パソコンから「http://<IPアドレス>」にアクセスできることを確認。

表示画面は、APモードでブラウザから「http://192.168.4.1」にアクセスする際と同じです。

 

C.H.I.P. (8) BMP280 i2c

OLED繋いだから、早速同じi2cのBMP280を試す。

chen@chip:~$ git clone https://github.com/prisme60/BMP280.git

コメントに書いてる方法でコンパイル

chen@chip:~/BMP280$ gcc -Wall -o BMP280 ./BMP280.c
./BMP280.c: In function ‘main’:
./BMP280.c:339:2: error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode
for(int i = 0; i < argc; i++) {
^
./BMP280.c:339:2: note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your code
./BMP280.c:371:4: error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode
for(int i=0;i<20;i++) {
^

エラーがたくさんある。オプションがつければいいらしい。

chen@chip:~/BMP280$ vi BMP280.c

でもソースを斜めてみると、二箇所だけfor文に定義するから、簡単に直せる。ただ定義文を関数先頭に書くだけ。

chen@chip:~/BMP280$ gcc -Wall -o BMP280 ./BMP280.c
chen@chip:~/BMP280$ ./BMP280

i2c_Open : Failed to open the i2c bus, error : 13
Check to see if you have a bus: /dev/i2c-1
This is not a slave device problem, I can not find the bus/port with which to talk to the device

sudoじゃないとダメだね。

chen@chip:~/BMP280$ sudo ./BMP280

Device accessed via File descriptor:3 at Address:0x76 has returned:0
[0]=3 [1]=6E [2]=B5 [3]=66 [4]=32 [5]=0
T1=28163 T2=26293 T3=50
P1=38053 P2=-10790 P3=3024 P4=7462 P5=-175 P6=-7 P7=15500 P8=-14600 P9=6000
adc_Temperature=536630 adc_Pressure=311387
{“temperature”:26.96,”Pressure64″:1017.5,”Pressure32″:1017.5,”PressureDouble”:1017.5}
adc_Temperature=536636 adc_Pressure=311390
{“temperature”:26.97,”Pressure64″:1017.5,”Pressure32″:1017.5,”PressureDouble”:1017.5}
adc_Temperature=536636 adc_Pressure=311390
{“temperature”:26.97,”Pressure64″:1017.5,”Pressure32″:1017.5,”PressureDouble”:1017.5}

延々と続く…