Showing posts with label NodeMCU. Show all posts
Showing posts with label NodeMCU. Show all posts

Sunday, August 16, 2020

NodeMCU (ESP8266) + 1.44" 128x128 TFT with ST7735 SPI driver (KMR1441_SPI V2)





This video show how to driver 1.44" 128x128 TFT with ST7735 SPI driver (KMR1441_SPI V2) with NodeMCU (ESP8266) using ssd1306 library. Using Arduino IDE.

- In Arduino IDE, open library manager, search ST7735, and install ssd1306 library.

- Open Example > ssd1306 > demos > st7735_demo

- Connect ESP8266 to LCD
ESP8266 LCD
===================
3V3 VCC
GND GND
D1 A0 (D/C)
D2 CS (CS)
RX RESET (RES)
D7 SDA (DIN)
D5 SCK (CLK)
LED (Open in my test)

Monday, May 18, 2020

ESP8266 (NodeMCU) - Get current weather data from OpenWeatherMap, using ArduinoJson

This exercise run on ESP8266 (NodeMCU), to get current weather data from OpenWeatherMap.


OpenWeatherMap provide easy-to-work weather APIs. Before you can use the APIs, you have to sign-up your account with email, for free.

After sign-up, and email varified, you can get various weather info using APIs with your api key. For example to get current weather:
http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=<your key here>

This example with your api key will be sent you in the confirm email. You can paste it in browser, to receive the response in JSON form.


Copy the returned JSON to the input box in ArduinoJson Assistant, it will return you the Memory pool size, and example to Parsing program.





ArduinoJson is a simple and efficient JSON library for embedded C++. Support various platforms of Arduino framework. Already included in Platform IO.



For connection between ESP8266 and the I2C OLED, refer last post "ESP8266 (NodeMCU/ESP8266 DevKitC) + SSD1306 I2C OLED, Platform IO".

Here is my exercise run on ESP8266 (NodeMCU), to get current weather data from OpenWeatherMap, using libraries ESP8266WiFi, ESP8266HTTPClient, ArduinoJson, and display on I2C OLED using library ESP8266_SSD1306.

#include <Arduino.h>
#include "SSD1306Wire.h"
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

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

const String api_1 = "http://api.openweathermap.org/data/2.5/weather?q=";
const String qLocation = "London,uk";
const String api_2 = "&units=metric"; //request return temp in celsius
const String api_3 = "&APPID=";
const String api_key = "09816ba66b72ec172f3b8e1982c962ff";  //your api key
const String rqs = api_1 + qLocation + api_2 + api_3 + api_key;

SSD1306Wire  display(0x3c, D3, D5);

//Visit ArduinoJson Assistant (https://arduinojson.org/v6/assistant/)
//To get Memory pool size
StaticJsonDocument<800> doc;

void sendRqs(){

  HTTPClient http;
  http.begin(rqs);
  int httpCode = http.GET();

  if (httpCode > 0) { 

    String response = http.getString();
    //display.clear();
    //display.drawString(0, 0, "response:");
    //display.drawString(0, 10, response);
    //display.display();

    Serial.println(response);

    // Deserialize the JSON document
    DeserializationError error = deserializeJson(doc, response);

    // Test if parsing succeeds.
    if (error) {

      String errorStr = error.c_str();

      display.clear();
      display.drawString(0, 0, "deserializeJson() error:");
      display.drawString(0, 10, errorStr);
      display.display();

      Serial.println(errorStr);

      delay(10000);
    }else{
      Serial.println("deserializeJson() no error.");

      //--- Copy from ArduinoJson Assistant
      float coord_lon = doc["coord"]["lon"];
      float coord_lat = doc["coord"]["lat"];

      JsonObject weather_0 = doc["weather"][0];
      int weather_0_id = weather_0["id"];
      const char* weather_0_main = weather_0["main"];
      const char* weather_0_description = weather_0["description"];
      const char* weather_0_icon = weather_0["icon"];

      const char* base = doc["base"];

      JsonObject main = doc["main"];
      float main_temp = main["temp"];
      float main_feels_like = main["feels_like"];
      float main_temp_min = main["temp_min"];
      float main_temp_max = main["temp_max"];
      int main_pressure = main["pressure"];
      int main_humidity = main["humidity"];

      int visibility = doc["visibility"];

      float wind_speed = doc["wind"]["speed"];
      int wind_deg = doc["wind"]["deg"];

      int clouds_all = doc["clouds"]["all"];

      long dt = doc["dt"];

      JsonObject sys = doc["sys"];
      int sys_type = sys["type"];
      int sys_id = sys["id"];
      const char* sys_country = sys["country"];
      long sys_sunrise = sys["sunrise"];
      long sys_sunset = sys["sunset"];

      int timezone = doc["timezone"];
      long id = doc["id"];
      const char* name = doc["name"];
      int cod = doc["cod"];

      //--- End of ArduinoJson Assistant ---

      // Print values.
      Serial.println("temp_min: " + String(main_temp_min));
      Serial.println("temp_max: " + String(main_temp_max));

      display.clear();
      display.drawString(0, 0, name);
      display.drawString(0, 10, "temp_min: " + String(main_temp_min));
      display.drawString(0, 20, "temp_max: " + String(main_temp_max));

      display.display();
    }

  }else{
    display.clear();
    display.drawString(0, 0, "http.GET() == 0");
    display.display();
    Serial.println("http.GET() == 0");
  }
  
  http.end();   //Close connection

}

void setup() {

  Serial.begin(9600);

  display.init();
  display.setContrast(255);
  display.clear();

  display.drawString(0, 0, "ESP32/OLED");
  display.display();

  WiFi.begin(ssid, password);
  display.drawString(0, 10, "Connecting...");
  display.display();
  while (WiFi.status() != WL_CONNECTED) {
    delay(800);
  }
}

void loop() {
  display.clear();
  if (WiFi.status() == WL_CONNECTED) {
    display.drawString(0, 0, "CONNECTED");
    display.display();

    sendRqs();

  }else{
    display.drawString(0, 0, "NOT CONNECTED");
    display.display();
  }
  
  Serial.println("DONE");
  delay(10000);
}




Saturday, May 16, 2020

ESP8266 (NodeMCU/ESP8266 DevKitC) + SSD1306 I2C OLED, Platform IO.

NodeMCU + SSD1306 I2C OLED

Steps to new a PlatformIO project, for NodeMCU board of Arduino framework, using library and example of ESP8266_SSD1306, to display on I2C SSD1306 OLED display. Tested on Windows 10/VirtualBox.


- Connect NodeMCU to I2C SSD1306 OLED:


- Refer to previous post to Install VS Code/PlatformIO IDE on Ubuntu 20.04.

- Make sure the library ESP8266_SSD1306 is installed.


- Create a new project using NodeMCU board and Arduino framework.

- Open PlatformIO - Libraries page, copy example of ESP8266_SSD1306 library to our main.c.

- Edit platformio.ini to specify upload_port.

- Finally, Build and Upload. Done.


Espressif ESP8266 DevKitC + SSD1306 I2C OLED

Then I tried to test it on Espressif ESP8266 DevKitC, with module ESP-WROOM-02D.

It's found from ESP-WROOM-02D/02U Datasheet, I2C is assigned to IO14 (SCL), IO2 (SDA).


So I re-connect accordingly.

ESP8266 DevKitC <-> I2C SSD1306 OLED
3V3 - VCC
GND - GND
IO2 - SDA
IO14 - SCL

And edit main.c, change the code:

from:
SSD1306Wire  display(0x3c, D3, D5);

to:
SSD1306Wire  display(0x3c, 2, 14);


Re-build, and upload...done.


Next:
ESP8266 (NodeMCU) - Get current weather data from OpenWeatherMap, using ArduinoJson


Saturday, January 19, 2019

NodeMCU-32S (ESP32-S)

Just bought a NodeMCU-32S board. NodeMCU-32S is the core development board based on ESP-32S module.



Pin definition (from www.ai-thinker.com)



Related link:
ai-thinker NodeMCU-32S page

Exercise using NodeMCU-32S (ESP32-S):

Thursday, June 15, 2017

ESP8266/NodeMCU read Analog Input and send to Raspberry Pi via Serial/USB

This example of ESP8266/NodeMCU read input from A0, and output to Serial. The receiving side is a Raspberry Pi 3 running Raspbian Jessie with PIXEL and Arduino IDE installed, the result is display graphically using Arduino IDE's Serial Plotter. All job done on Raspberry Pi 3. ESP8266/NodeMCU connect to the Raspberry Pi 3 with USB.


To run the whole in Raspberry Pi, you have to:
- Install Arduino IDE on Raspberry Pi/Raspbian Jessie with PIXEL
Add Arduino core for ESP8266 to Arduino IDE

The simple program run on ESP8266/NodeMCU, ESP8266_AnalogIn_SerialOut.ino. (Suppose it work on other Arduino also, such as Uno.)
const int analogIn = A0;
int analogVal = 0;
bool led = 1;

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {

  digitalWrite(LED_BUILTIN, led);
  led = !led; 
  analogVal = analogRead(analogIn);
  Serial.println(analogVal);
  delay(500);
}

Next:
A Python example run on Raspberry Pi 3/Raspbian Jessie with PIXEL, to plot the serial data graphically using matplotlib library.

Thursday, June 1, 2017

NodeMCU/ESP8266 Arduino Core example, simple http server to output PWM

Last post show a dummy example of NodeMCU/ESP8266 Arduino Core to output PWM to control color/brightness of RGB LED.

It's another example to setup a simple HTTP-like server, to receive request from client, output PWM, to control color/brightness of RGB LED.


NodeMCU_WiFiWebServer_RGB.ino
/*
 *  This sketch run on NodeMCU (ESP8266),
 *  demonstrates how to set up a simple HTTP-like server.
 *  The server will set a GPIO pins depending on the request,
 *  to control the brightness of RGB LED connected to:
 *    D0 : BLUE
 *    D1 : GREEN
 *    D2 : RED
 *    
 *    http://server_ip/rgb/rrggbb/
 *    where rr is the value set RED
 *    where gg is the value set GREEN
 *    where bb is the value set BLUE
 *    then terminate with '/'
 *  server_ip is the IP address of the NodeMCU, will be 
 *  printed to Serial when the module is connected.
 */

#include <ESP8266WiFi.h>

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

int ledB = D0;
int ledG = D1;
int ledR = D2;

// 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 GPIOs for RGB LED
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  analogWriteRange(99); //PWM: 0~99
  
  // 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 valR, valG, valB;
  String subStringR, subStringG, subStringB;
  int index = req.indexOf("/rgb/");
  if(index != -1){
    if(req.charAt(index+11)=='/'){
      subStringR = req.substring(index+5, index+7);
      subStringG = req.substring(index+7, index+9);
      subStringB = req.substring(index+9, index+11);
      Serial.println("R: " + subStringR);
      Serial.println("G: " + subStringG);
      Serial.println("B: " + subStringB);

      valR = subStringR.toInt();
      valG = subStringG.toInt();
      valB = subStringB.toInt();
      Serial.println("valR: " + String(valR));
      Serial.println("valG: " + String(valG));
      Serial.println("valB: " + String(valB));
      
    }
    else{
      Serial.println("Not terminated with /");
      client.stop();
      return;
    }
  }
  else {
    Serial.println("No /rgb/ found");
    client.stop();
    return;
  }

  // Set GPIOs according to the request
  // No check valid of the requested setting
  analogWrite(ledR, valR);
  analogWrite(ledG, valG);
  analogWrite(ledB, valB);
  
  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\nGPIOs of RGB is now ";
  s += String(valR) +":" + String(valG) + ":" + String(valB);
  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
}


Connection same as in last post:



Compare with ESP32 version: ESP32/Arduino core for ESP32 example, simple Web control RGB LED

NodeMCU/ESP8266 Arduino Core analog output PWM

Example of NodeMCU with ESP8266 Arduino Core to output PWM by calling analogWrite(), to control brightness of RGB LED.



NodeMCU_PWM.inf
int ledB = D0;
int ledG = D1;
int ledR = D2;

void setup() {
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  //Set PWM frequency 500, default is 1000
  //Set range 0~100, default is 0~1023
  analogWriteFreq(500);
  analogWriteRange(100);
}

// the loop function runs over and over again forever
void loop() {
  analogWrite(ledR, 0);
  analogWrite(ledG, 0);
  analogWrite(ledB, 0);
  delay(500);
  analogWrite(ledR, 100);
  analogWrite(ledG, 100);
  analogWrite(ledB, 100);
  delay(500);
  analogWrite(ledR, 0);
  analogWrite(ledG, 0);
  analogWrite(ledB, 0);
  delay(500);

  int i;
  for(i=0; i<100; i++){
    analogWrite(ledR, i);
    delay(10);
  }
  analogWrite(ledR, 0);
  
  for(i=0; i<100; i++){
    analogWrite(ledG, i);
    delay(10);
  }
  analogWrite(ledG, 0);
  
  for(i=0; i<100; i++){
    analogWrite(ledB, i);
    delay(10);
  }
  analogWrite(ledB, 0);

  for(i=0; i<100; i++8){
    analogWrite(ledR, i);
    analogWrite(ledG, i);
    analogWrite(ledB, i);
    delay(10);
  }

  for(i=100; i>0; i--){
    analogWrite(ledR, i);
    analogWrite(ledG, i);
    analogWrite(ledB, i);
    delay(10);
  }

}

Reference:
analogWrite(pin, value) enables software PWM on the given pin. PWM may be used on pins 0 to 16. Call analogWrite(pin, 0) to disable PWM on the pin. value may be in range from 0 to PWMRANGE, which is equal to 1023 by default. PWM range may be changed by calling analogWriteRange(new_range).

PWM frequency is 1kHz by default. Call analogWriteFreq(new_frequency) to change the frequency.

Next:
simple http server to output PWM, to control color/brightness of RGB LED.


Tuesday, May 23, 2017

Control GPIOs of NodeMCU (ESP8266) with ESP8266 core for Arduino, to read Buttons and write LEDs

This example show how to read input (D5, D6 & D7) from buttons, and write output (D0, D1 & D2) to LEDs accordingly. For the input, all set INPUT_PULLUP to enable internal pull-up resistor, so no external resistors needed.


Connection:

/*
NodeMCU IO index vs ESP8266 pin
IO index  ESP8266 pin
    0     [*] GPIO16
    1     GPIO5 
    2     GPIO4 
    3     GPIO0
    4     GPIO2
    5     GPIO14  
    6     GPIO12
    7     GPIO13
    8     GPIO15
    9     GPIO3
    10    GPIO1
    11    GPIO9
    12    GPIO10
[*] D0(GPIO16) can only be used as gpio read/write. 
No support for open-drain/interrupt/pwm/i2c/ow.
https://nodemcu.readthedocs.io/en/master/en/modules/gpio/
 */
 
void setup() {
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  pinMode(D5, INPUT_PULLUP);
  pinMode(D6, INPUT_PULLUP);
  pinMode(D7, INPUT_PULLUP);
}

// the loop function runs over and over again forever
void loop() {
  if(digitalRead(D5)){
    digitalWrite(D0, LOW);
  }else{
    digitalWrite(D0, HIGH);
  }

  if(digitalRead(D6)){
    digitalWrite(D1, LOW);
  }else{
    digitalWrite(D1, HIGH);
  }

  if(digitalRead(D7)){
    digitalWrite(D2, LOW);
  }else{
    digitalWrite(D2, HIGH);
  }

}


Usage of GPIO:
At the beginning, I want to use D6, D7 and D8 as input. But D8 always return LOW. After googled and found schematic diagram of NodeMCU DevKit v1.0 here: https://github.com/nodemcu/nodemcu-devkit-v1.0/blob/master/NODEMCU_DEVKIT_V1.0.PDF. It's found that GPIO15 (D8) connect to GND via a resistor, so always return LOW.

And MATTERS NEEDING ATTENTION can be found in the schematic diagram:
On every boot/reset/wakeup, GPIO15 MUST keep LOW, GPIO2 MUST keep HIGH. 
GPIO0 HIGH -> RUN MODE, LOW -> FLASH MODE.
When you need to use the sleep mode, GPIO16 and RST should be connected, and GPIO16 will output LOW to reset the system at the time of wakeup.

So, I change using D5.


Wednesday, May 10, 2017

Control GPIO (external IO pins) of NodeMCU (ESP8266) with ESP8266 core for Arduino


With ESP8266 core for Arduino, we can load and run the build-in basic example of "Blink" on NodeMCU to toggle the on board LED. We can also employ the same methods to control other io pin, or GPIO.



Connection:



There are many version of ESP8266, the printed mark on PCB may not the io number of ESP8266 MCU, you have to check it for your board. This example run on NodeMCU with marking and CPU pin assignment:
NodeMCU IO index vs ESP8266 pin
IO index  ESP8266 pin
    0     [*] GPIO16  
    1     GPIO5 
    2     GPIO4 
    3     GPIO0 
    4     GPIO2 
    5     GPIO14  
    6     GPIO12
    7     GPIO13
    8     GPIO15
    9     GPIO3
    10    GPIO1
    11    GPIO9
    12    GPIO10
[*] D0(GPIO16) can only be used as gpio read/write. 
No support for open-drain/interrupt/pwm/i2c/ow.
https://nodemcu.readthedocs.io/en/master/en/modules/gpio/

If you run on NodeMCU and select board of NodeMCU 1.0, you can use D1~D10 to access the pins. Refer to pins_arduino.h. Both D1 and 5 refer to the same pin.



If you run on other module, and select other board, may be the compile will report error of  'D1' was not declared in this scope. You have to specify the io# of the MCU, 5 in this case.


NodeMCU_Blink.ino
/*
NodeMCU IO index vs ESP8266 pin
IO index  ESP8266 pin
    0     [*] GPIO16  
    1     GPIO5 
    2     GPIO4 
    3     GPIO0 
    4     GPIO2 
    5     GPIO14  
    6     GPIO12
    7     GPIO13
    8     GPIO15
    9     GPIO3
    10    GPIO1
    11    GPIO9
    12    GPIO10
[*] D0(GPIO16) can only be used as gpio read/write. 
No support for open-drain/interrupt/pwm/i2c/ow.
https://nodemcu.readthedocs.io/en/master/en/modules/gpio/
 */

/*
 * For NodeMCU (8266) both D1 and 5 refer to the same pin
 * For others, such as "Generic ESP8266 Module", it will
 * report error of: 'D1' was not declared in this scope.
 */
const int io5 = 5;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pins as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  //pinMode(D1, OUTPUT);
  pinMode(io5, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  //digitalWrite(D1, HIGH);
  digitalWrite(io5, HIGH);
  delay(500);
  //digitalWrite(D1, LOW);
  digitalWrite(io5, LOW);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  //digitalWrite(D1, HIGH);
  digitalWrite(io5, HIGH);
  delay(500);
  //digitalWrite(D1, LOW);
  digitalWrite(io5, LOW);
  delay(500);
}

Next:
Control GPIOs of NodeMCU (ESP8266) with ESP8266 core for Arduino, to read Buttons and write LEDs

Monday, June 20, 2016

NodeMCU/ESP8266 + OLED 1.3" 128x64 SPI SH1106, using esp8266-oled-sh1106 library


It's a 1.3" 128x64 OLED of SPI interface, with SH1106 controller. The SH1106 is in general similar to the SSD1306. Main difference is a memory of 132x64 instead of 128x64.

This post show how to connect with NodeMCU and install the library of esp8266-oled-sh1106.

Connection between NodeMCU and the 1.3" 128x64 OLED SPI module with SH1106:
 D5 GPIO14   CLK         - D0 pin OLED display
 D6 GPIO12   MISO (DIN)  - not connected
 D7 GPIO13   MOSI (DOUT) - D1 pin OLED display
 D1 GPIO5    RST         - RST pin OLED display
 D2 GPIO4    DC          - DC pin OLED
 D8 GPIO15   CS / SS     - CS pin OLED display


Download and install the library as shown, and run the example:



Related:
Hello World 1.3 inch IIC/SPI 128x64 OLED x Arduino, using u8glib library
NodeMCU/ESP8266 + OLED 0.96" 128x64 I2C SSD1306 using esp8266-oled-ssd1306 library

Sunday, June 19, 2016

NodeMCU/ESP8266 + OLED 0.96" 128x64 I2C SSD1306 using esp8266-oled-ssd1306 library


esp8266-oled-ssd1306 is  a driver for the SSD1306 based 128x64 pixel OLED display running on the Arduino/ESP8266 platform. Can be used with either the I2C or SPI version of the display

You can either download this library as a zip file and unpack it to your Arduino/libraries folder or (once it has been added) choose it from the Arduino library manager.

This video show how to install on Arduino IDE using Library Manager, and run the example.


Connection between NodeMCU and OLED 0.96" 128x64 I2C SSD1306:
NodeMCU 3V3 - OLED VCC
NodeMCU GND - OLED GND
NodeMCU D3 - OLED SDA
NodeMCU D5 - OLED SCL

(The Fritzing parts of both nodemcu-v1.0 and OLED_SSD1306_I2C_128x64 can be download here:
https://github.com/squix78/esp8266-fritzing-parts)


Related:
NodeMCU/ESP8266 display on 1.3" 128x64 OLED SPI with SH1106, using esp8266-oled-sh1106 library
Raspberry Pi display on 128x64 I2C OLED with SSD1306, using Python

Other libraries to run on NodeMCU/ESP8266 with I2C OLED SSD1306:
NodeMCU (ESP8266) to display on 128x64 I2C OLED, using Adafruit SSD1306 library
esp8266-OLED, esp8266-Arduino library for I2C-OLED displays

For ESP32 WiFi/Bluetooth Module:
Connect I2C 128X64 OLED (SSD1306) to ESP32, using esp8266-oled-ssd1306

Tuesday, May 10, 2016

NodeMCU/ESP8266 WebSocketsServer, load html from separate file in flash file system


This example have the same function of "NodeMCU/ESP8266 implement WebSocketsServer to control RGB LED", but the html is saved in separate file in flash file system instead of hard code in ino.


Prepare the html in data directory under sketch directory:

data/home.html
<html>
<head>
<script>
var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);
connection.onopen = function(){
    connection.send('Connect ' + new Date()); 
};

connection.onerror = function(error){
    console.log('WebSocket Error ', error);
};

connection.onmessage = function(e){
    console.log('Server: ', e.data);
};

function sendRGB(){
    var r = parseInt(document.getElementById('r').value).toString(16);
    var g = parseInt(document.getElementById('g').value).toString(16);
    var b = parseInt(document.getElementById('b').value).toString(16);
    
    if(r.length < 2){
        r = '0' + r;
    }   
    
    if(g.length < 2){
        g = '0' + g;
    }   
    
    if(b.length < 2){
        b = '0' + b;
    }   
    
    var rgb = '#'+r+g+b;    
    console.log('RGB: ' + rgb); 
    connection.send(rgb);
}
</script>
</head>
<body>
<b>LED Control 2:</b><br/>
<i>Load html from separate file</i><br/>
<br/>
R: <input id="r" type="range" min="0" max="255" step="1" onchange="sendRGB();" /><br/>
G: <input id="g" type="range" min="0" max="255" step="1" onchange="sendRGB();" /><br/>
B: <input id="b" type="range" min="0" max="255" step="1" onchange="sendRGB();" /><br/>
<br/>
http://arduino-er.blogspot.com/
</body>
</html>

To upload this sketch data of html, refer last post "NodeMCU/ESP8266 read from separate file in Flash File System".

Modify the ino to load String of html from external file.

WebSocketServer_LEDcontrol.ino
//NodeMCU/ESP8266 implement WebSocketsServer to control RGB LED
//arduino-er.blogspot.com

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Hash.h>

#include "FS.h"

#define LED_RED     15
#define LED_GREEN   12
#define LED_BLUE    13

ESP8266WiFiMulti WiFiMulti;

ESP8266WebServer server = ESP8266WebServer(80);
WebSocketsServer webSocket = WebSocketsServer(81);

String html_home;

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {

    switch(type) {
        case WStype_DISCONNECTED:
            Serial.printf("[%u] Disconnected!\n", num);
            break;
        case WStype_CONNECTED: {
            IPAddress ip = webSocket.remoteIP(num);
            Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);

            // send message to client
            webSocket.sendTXT(num, "Connected");
        }
            break;
        case WStype_TEXT:
            Serial.printf("[%u] get Text: %s\n", num, payload);

            if(payload[0] == '#') {
                // we get RGB data

                // decode rgb data
                uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);

                analogWrite(LED_RED,    ((rgb >> 16) & 0xFF));
                analogWrite(LED_GREEN,  ((rgb >> 8) & 0xFF));
                analogWrite(LED_BLUE,   ((rgb >> 0) & 0xFF));
            }

            break;
    }

}

void prepareFile(){
  
  Serial.println("Prepare file system");
  SPIFFS.begin();
  
  File file = SPIFFS.open("/home.html", "r");
  if (!file) {
    Serial.println("file open failed");  
  } else{
    Serial.println("file open success");

    html_home = "";
    while (file.available()) {
      //Serial.write(file.read());
      String line = file.readStringUntil('\n');
      html_home += line + "\n";
    }
    file.close();

    Serial.print(html_home);
  }
}

void setup() {
    //Serial.begin(921600);
    Serial.begin(115200);

    //Serial.setDebugOutput(true);

    Serial.println();
    Serial.println();
    Serial.println();

    for(uint8_t t = 4; t > 0; t--) {
        Serial.printf("[SETUP] BOOT WAIT %d...\n", t);
        Serial.flush();
        delay(1000);
    }

    pinMode(LED_RED, OUTPUT);
    pinMode(LED_GREEN, OUTPUT);
    pinMode(LED_BLUE, OUTPUT);

    digitalWrite(LED_RED, 1);
    digitalWrite(LED_GREEN, 1);
    digitalWrite(LED_BLUE, 1);

    
    prepareFile();

    WiFi.softAP("arduino-er", "12345678");
    IPAddress myIP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(myIP);

    // start webSocket server
    webSocket.begin();
    webSocket.onEvent(webSocketEvent);

    if(MDNS.begin("esp8266")) {
        Serial.println("MDNS responder started");
    }

    // handle index
    server.on("/", []() {
        // send home.html
        server.send(200, "text/html", html_home);
    });

    server.begin();

    // Add service to MDNS
    MDNS.addService("http", "tcp", 80);
    MDNS.addService("ws", "tcp", 81);

    digitalWrite(LED_RED, 0);
    digitalWrite(LED_GREEN, 0);
    digitalWrite(LED_BLUE, 0);

    Serial.printf("Server Start\n");

}

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



- more example of "ESP8266 core for Arduino".

NodeMCU/ESP8266 read from separate file in Flash File System


This example show how NodeMCU/ESP8266 read separate file in Flash File System.

In order to upload extra files to NodeMCU/ESP8266, a tool "ESP8266FS" is needed:

ESP8266FS is a tool which integrates into the Arduino IDE. It adds a menu item to Tools menu for uploading the contents of sketch data directory into ESP8266 flash file system.
  • Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.2.0/ESP8266FS-0.2.0.zip.
  • In your Arduino sketchbook directory, create tools directory if it doesn't exist yet
  • Unpack the tool into tools directory (the path will look like <home_dir>/Arduino/tools/ESP8266FS/tool/esp8266fs.jar)
  • Restart Arduino IDE
  • Open a sketch (or create a new one and save it)
  • Go to sketch directory (choose Sketch > Show Sketch Folder)
  • Create a directory named data and any files you want in the file system there
  • Make sure you have selected a board, port, and closed Serial Monitor
  • Select Tools > ESP8266 Sketch Data Upload. This should start uploading the files into ESP8266 flash file system. When done, IDE status bar will display SPIFFS Image Uploaded message.
ref: https://esp8266.github.io/Arduino/versions/2.1.0/doc/filesystem.html

This video show how to:


Example to read text file, test.txt, from Flash File System:

ESP_ext_file.ino
//arduino-er.blogspot.com
//To read separate file in file system
#include "FS.h"

void prepareFile(){
  
  Serial.println("Prepare file system");
  SPIFFS.begin();
  
  File file = SPIFFS.open("/test.txt", "r");
  if (!file) {
    Serial.println("file open failed!");  
  } else{
    Serial.println("file open success:)");

    while (file.available()) {
      Serial.write(file.read());
    }
    file.close();
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("To read separate file in file system");
  prepareFile();
}

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

}


Saturday, May 7, 2016

NodeMCU/ESP8266 implement WebSocketsServer to control RGB LED


In the previous example "NodeMCU/ESP8266 act as AP (Access Point) and web server to control GPIO", every time user click to change GPIO the page will be reloaded. This example use WebSocket, such that no need reload page.


Add WebSockets library to Arduino Software. To run on ESP devices, add version 2.x.x.
reference: https://github.com/Links2004/arduinoWebSockets


Open WebSockets example WebSocketServer_LEDcontrol. It's a WebSocketServer example to control RGB LED.


In my case, it cannot connect to my HotSpot shared by ASUS Zenfone 2 running Android 5.0! So I modify it to act as Access Point (AP).

WebSocketServer_LEDcontrol.ino
/*
 * WebSocketServer_LEDcontrol.ino
 *
 *  Created on: 26.11.2015
 *
 */
//Modified to act as AP
//arduino-er.blogspot.com

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Hash.h>

#define LED_RED     15
#define LED_GREEN   12
#define LED_BLUE    13

#define USE_SERIAL Serial


ESP8266WiFiMulti WiFiMulti;

ESP8266WebServer server = ESP8266WebServer(80);
WebSocketsServer webSocket = WebSocketsServer(81);

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {

    switch(type) {
        case WStype_DISCONNECTED:
            USE_SERIAL.printf("[%u] Disconnected!\n", num);
            break;
        case WStype_CONNECTED: {
            IPAddress ip = webSocket.remoteIP(num);
            USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);

            // send message to client
            webSocket.sendTXT(num, "Connected");
        }
            break;
        case WStype_TEXT:
            USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);

            if(payload[0] == '#') {
                // we get RGB data

                // decode rgb data
                uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);

                analogWrite(LED_RED,    ((rgb >> 16) & 0xFF));
                analogWrite(LED_GREEN,  ((rgb >> 8) & 0xFF));
                analogWrite(LED_BLUE,   ((rgb >> 0) & 0xFF));
            }

            break;
    }

}

void setup() {
    //USE_SERIAL.begin(921600);
    USE_SERIAL.begin(115200);

    //USE_SERIAL.setDebugOutput(true);

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

    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }

    pinMode(LED_RED, OUTPUT);
    pinMode(LED_GREEN, OUTPUT);
    pinMode(LED_BLUE, OUTPUT);

    digitalWrite(LED_RED, 1);
    digitalWrite(LED_GREEN, 1);
    digitalWrite(LED_BLUE, 1);

    /*
    WiFiMulti.addAP("SSID", "passpasspass");

    while(WiFiMulti.run() != WL_CONNECTED) {
        delay(100);
    }
    */

    WiFi.softAP("arduino-er", "12345678");
    IPAddress myIP = WiFi.softAPIP();
    USE_SERIAL.print("AP IP address: ");
    USE_SERIAL.println(myIP);

    // start webSocket server
    webSocket.begin();
    webSocket.onEvent(webSocketEvent);

    if(MDNS.begin("esp8266")) {
        USE_SERIAL.println("MDNS responder started");
    }

    // handle index
    server.on("/", []() {
        // send index.html
        // replace for better looking
        server.send(200, "text/html", 
        "<html><head><script>"
        "var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);"
        "connection.onopen = function () {  connection.send('Connect ' + new Date()); };"
        "connection.onerror = function (error) {    console.log('WebSocket Error ', error);};"
        "connection.onmessage = function (e) {  console.log('Server: ', e.data);};"
        "function sendRGB() {  "
        "var r = parseInt(document.getElementById('r').value).toString(16);  "
        "var g = parseInt(document.getElementById('g').value).toString(16);  "
        "var b = parseInt(document.getElementById('b').value).toString(16);  "
        "if(r.length < 2) { r = '0' + r; }   "
        "if(g.length < 2) { g = '0' + g; }   "
        "if(b.length < 2) { b = '0' + b; }   "
        "var rgb = '#'+r+g+b;    "
        "console.log('RGB: ' + rgb); "
        "connection.send(rgb); }"
        "</script></head><body>"
        "LED Control:<br/><br/>"
        "R: ""<input id=\"r\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" onchange=\"sendRGB();\" /><br/>"
        "G: <input id=\"g\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" onchange=\"sendRGB();\" /><br/>"
        "B: <input id=\"b\" type=\"range\" min=\"0\" max=\"255\" step=\"1\" onchange=\"sendRGB();\" /><br/>"
        "</body></html>");
    });

    server.begin();

    // Add service to MDNS
    MDNS.addService("http", "tcp", 80);
    MDNS.addService("ws", "tcp", 81);

    digitalWrite(LED_RED, 0);
    digitalWrite(LED_GREEN, 0);
    digitalWrite(LED_BLUE, 0);

}

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


Connection:


Connect your mobile to the AP "arduino-er" with password "12345678", open browser and visit IP 192.168.4.1. Then you can control the RGB LED in web page. As shown in the video, more than one device can connect to and control the RGB LED at the same time.

This example hard-code the html inside ino. The next example show how to "load html from separate file in flash file system".

- more example of "ESP8266 core for Arduino".



Updated@2017-06-18:
What is WStype_t (WStype_DISCONNECTED, WStype_CONNECTED...)?

WStype_t is:
typedef enum {
    WStype_ERROR,
    WStype_DISCONNECTED,
    WStype_CONNECTED,
    WStype_TEXT,
    WStype_BIN
} WStype_t;

Should be defined at your Documents\Arduino\libraries\WebSockets\src\WebSockets.h

You should have a example at File > Examples > WebSockets > WebSocketClient to show how to use it.


Tuesday, May 3, 2016

NodeMCU/ESP8266 act as AP (Access Point) and web server to control GPIO

Further works on previous exercise "NodeMCU/ESP8266 act as AP (Access Point) and simplest Web Server"; this example of NodeMCU/ESP8266 act as AP and implement a web server to control GPIO (on-board LED) using HTML interface.


ESP_AP_WebServer.ino
/*
 * NodeMCU/ESP8266 act as AP (Access Point) and simplest Web Server
 * to control GPIO (on-board LED)
 * Connect to AP "arduino-er", password = "password"
 * Open browser, visit 192.168.4.1
 */
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>

const char *ssid = "arduino-er";
const char *password = "password";
int stateLED = LOW;

ESP8266WebServer server(80);

void handleRoot() {
    response();
}

void handleLedOn() {
  stateLED = LOW;
  digitalWrite(LED_BUILTIN, stateLED);
  response();
}

void handleLedOff() {
  stateLED = HIGH;
  digitalWrite(LED_BUILTIN, stateLED);
  response();
}

const String HtmlHtml = "<html><head>"
    "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /></head>";
const String HtmlHtmlClose = "</html>";
const String HtmlTitle = "<h1>Arduino-er: ESP8266 AP WebServer exercise</h1><br/>\n";
const String HtmlLedStateLow = "<big>LED is now <b>ON</b></big><br/>\n";
const String HtmlLedStateHigh = "<big>LED is now <b>OFF</b></big><br/>\n";
const String HtmlButtons = 
    "<a href=\"LEDOn\"><button style=\"display: block; width: 100%;\">ON</button></a><br/>"
    "<a href=\"LEDOff\"><button style=\"display: block; width: 100%;\">OFF</button></a><br/>";

void response(){
  String htmlRes = HtmlHtml + HtmlTitle;
  if(stateLED == LOW){
    htmlRes += HtmlLedStateLow;
  }else{
    htmlRes += HtmlLedStateHigh;
  }

  htmlRes += HtmlButtons;
  htmlRes += HtmlHtmlClose;

  server.send(200, "text/html", htmlRes);
}

void setup() {
    delay(1000);
    Serial.begin(9600);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("visit: \n");
    Serial.println(apip);
    server.on("/", handleRoot);
    server.on("/LEDOn", handleLedOn);
    server.on("/LEDOff", handleLedOff);
    server.begin();
    Serial.println("HTTP server beginned");
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, stateLED);
}

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


Next:
NodeMCU/ESP8266 implement WebSocketsServer to control RGB LED


- more example of "ESP8266 core for Arduino".

Sunday, April 24, 2016

NodeMCU/ESP8266: get ESP chip and flash info

Simple sketch run on NodeMCU/ESP8266 to get chip and flash info.

ESP_GetFlashSize.ino
//reference: 
//http://esp8266.github.io/Arduino/versions/2.1.0/doc/libraries.html

void setup() {
  Serial.begin(9600);
  Serial.println();
  Serial.println();

  Serial.println("http://arduino-er.blogspot.com/");
  Serial.println("ESP chip and flash info");
  Serial.printf("The ESP8266 chip ID as a 32-bit integer:\t%08X\n", ESP.getChipId());
  Serial.printf("The flash chip ID as a 32-bit integer:\t\t%08X\n", ESP.getFlashChipId());
  Serial.printf("Flash chip frequency:\t\t\t\t%d (Hz)\n", ESP.getFlashChipSpeed());

  /* ESP.getFlashChipSize() returns the flash chip size, in bytes, 
   * as seen by the SDK (may be less than actual size).
   */
  Serial.printf("Flash chip size:\t\t\t\t%d (bytes)\n", ESP.getFlashChipSize());

  Serial.printf("Free heap size:\t\t\t\t\t%d (bytes)\n", ESP.getFreeHeap());

  
}

void loop() {
  

}

Tested on NodeMCU 1.0:


Monday, April 18, 2016

Hello World NodeMCU (ESP8266) + 128x64 I2C OLED, using Adafruit SSD1306 library

Minimum "Hello World" run on NodeMCU (ESP8266) + 128x64 I2C OLED:


To setup libraries for 128x64 I2C OLED, refer last post "NodeMCU (ESP8266) to display on 128x64 I2C OLED".

NodeMCU_OLED_helloworld.ino
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET LED_BUILTIN  //4
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  // Clear the buffer.
  display.clearDisplay();
  display.display();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Hello from:");
  display.println("http://arduino-er.blogspot.com/");
  display.display();

}

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

}

Sunday, April 17, 2016

NodeMCU (ESP8266) to display on 128x64 I2C OLED, using Adafruit SSD1306 library




This post show how to program NodeMCU (ESP8266) on Arduino IDE (with ESP8266 core for Arduino), to display on  0.96 inch 128X64 I2C OLED (base on SSD1306), using Adafruit SSD1306 and Adafruit GFX Libraries.

- It's assumed you are programming NodeMCU on Arduino Software, with ESP8266 core for Arduino installed.

- Connect I2C OLED to NodeMCU.


OLED VCC - NodeMCU 3v3
OLED GND - NodeMCU GND
OLED SCL - NodeMCU D1
OLED SDA - NodeMCU D2

(reamrk: the Fritzing parts of can OLED_SSD1306_I2C_128x64 can be download HERE)


- Add OLED library to Arduino Software:
* Open Library Manager in Arduino IDE, search SSD1306. You can find Adafruit SSD1306 library, SSD1306 OLED driver library for 'monochrome' 128x64 and 128x32 OLEDs. Install it.
* Install Adafruit GFX Library also.

- Open SSD1306 example:
File > Examples > Adafruit SSD1306 > ssd1306_128x64_i2c.

If you get error of "Height incorrect, please fix Adafruit_SSD1306.h!":
Open Adafruit_SSD1306.h file, in the path like "C:\Users\user\Documents\Arduino\libraries\Adafruit_SSD1306\Adafruit_SSD1306.h". Un-comment "#define SSD1306_128_64", and comment "#define SSD1306_128_32".


- Return to the Adafruit SSD1306 library again. Visit the web site of the library, https://github.com/adafruit/Adafruit_SSD1306. It's Tested Works on ESP8266 (Adafruit Huzzah), but have to change OLED_RESET to different pin if using default I2C pins D4/D5.

There are no RESET signal on my I2C OLED, so I assign it to any pin, LED_BUILTIN (the on-board LED).


- Make sure the I2C address is correct:
My I2C OLED have address 3C, correct the code display.begin(SSD1306_SWITCHCAPVCC, 0x3C);


- Finished.


more:
- Hello World NodeMCU (ESP8266) + 128x64 I2C OLED


Related:
- Another library of I2C OLED for ESP8266 core for Arduino - esp8266-OLED
esp8266-oled-ssd1306 library

Monday, April 4, 2016

NodeMCU act as WiFi client to update dweet.io



dweet.io is simple publishing and subscribing for machines, sensors, devices, robots, and gadgets (we just call them things). We call published messages ‘dweets’. It’s helpful to think of dweet.io as a Twitter for things, in fact.

I have a old example to show how to "Arduino Uno + Ethernet Shield send data to dweet.io and freeboard.io". It's a NodeMCU (with ESP8266 core for Arduino) version to update dweet.io.

You can visit following link on web browser to update dweet.io manually to test your url:
www.dweet.io/dweet/for/test_NodeMCU?A0=123

And check your thing at:
http://dweet.io/follow/test_NodeMCU

where testNodeMCU is the id of your thing in dweet.io, 123 is the value to update.

This code run on NodeMCU (suppose other standalone ESP8266 also), to connect to WiFi as client, read analog input from A0, and update dweet.io. (It's modified from Examples > ESP8266WiFi > WiFiClient,)


Connect analog input to A0, connection refer to last post "NodeMCU to read analog input, A0".

NodeMCU_WiFiClient_dweetio.ino
/*
 * reference: Examples > ESP8266WiFi > WiFiClient 
 */

#include <ESP8266WiFi.h>
const int AnalogIn  = A0;

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

const char* host = "www.dweet.io";
const char* thing  = "test_NodeMCU";
const char* thing_content = "A0";

void setup() {
  Serial.begin(115200);
  delay(10);

  // We start by connecting to a 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");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

int value = 0;

void loop() {
  delay(1000);
  value = analogRead(AnalogIn);

  Serial.print("connecting to ");
  Serial.println(host);
  
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }
  
  // We now create a URI for the request
  String url = "/dweet/for/";
  url += thing;
  url += "?";
  url += thing_content;
  url += "=";
  url += value;
  
  Serial.print("Requesting URL: ");
  Serial.println(url);
  
  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  int timeout = millis() + 5000;
  while (client.available() == 0) {
    if (timeout - millis() < 0) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }
  
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }
  
  Serial.println();
  Serial.println("closing connection");
}