Tag: Peripheral

Mi Flora and the ESP32

Mi Flora and the ESP32

I initially bought the ESP32 to connect to my Mi Flora sensors. So after I managed to figure out the basics for working with them, I wanted to dive right in and get the Mi Floras working.

First stop, search engine and of lucky for me, somebody already did a lot of the work. On GitHub, user sidddy has a working version of getting an ESP32 talking to a Mi Flora. This was an excellent start as it works quite nicely. The code is straight forward, the ESP wakes up, sets up wifi and bluetooth connection, connects to the Mi Flora, looks for the services it needs, posts the values on MQTT and sleeps again.

As I said, excellent starting point but I wanted a bit more. First, I found that the connection does not always succeed but since these ESPs are now hidden in my garden I wanted to know if the values of the Mi Floras were not updated in my domotica whether it was a problem of the ESP or the Mi Flora. To do that I modified the code so that it sends out an MQTT message with it’s own mac address so I know it was alive. Next, I wanted to have it query multiple Mi Floras. Actually I was hoping to have just one ESP32 for my garden but the range of the ESP32 and the Mi Flora was a bit shorter than I hoped. For me they needed to be at most about 3 meters apart.

I modified the code to sequentially poll 4 Mi Floras in one part of the garden. I managed to get this working only to find that sometimes it can ‘hang’ waiting on the right response from the Mi Flora. Instead of extending the time it stays awake, I decided I would try to poll them all but I would choose randomly from the devices that I did not yet poll. Once in operation, I also found that sometimes you get values that you do not want to have in your domotica environment, 0 degrees temperature (in Spring) or 0% humidity so I have added some checks around each value as well. If the range is off, it will just not post that particular value to MQTT. All in all I found that if I poll them every 30 minutes (a bit frequent, I know) than I have a pretty good chance of them reporting back at least once in every 2 hours which is the limit I have set in my domotica environment.

So the end result, which I have posted on github-mark-32pxGitHub, is an extension of the mentioned version and all credits go to sidddy as the only thing I did was add a bit of code around his ground work.

 

Advertisements
Photo resistors, in depth

Photo resistors, in depth

Some time ago I bought 50 photo resistors, 10 pieces of 5 different types each. Had no real need for that many but it’s very cheap if you buy them through AliExpress. It turned out to be quite difficult to find out which resistor does what. Tried looking for photoresistors, LDR, Light Dependent Resistor, photo cell but I could not find any explanation on the different types.

I did find the following information (the table is compiled from different sources):

Model Light resistance
(10 Lux) KOhm
Dark resistance
MOhm
GL5506 2-6 0.15
GL5516 5-10 0.5
GL5528 10-20 1
GL5537 16-50 2
GL5539 30-90 5

But how does that help in connecting these things? Well, I decided to connect these things, all at the same time and look at the readings.

So connecting, how do we do that? Well, we need to understand (somewhat) Ohm’s law. To measure the amount of light, we want to measure the resistance of the light sensor. Unfortunately the Arduino or the ESP8266 do not measure resistance. They can however measure the voltage on an analog port and this is where we need Ohm’s law. First, let’s look at a schematic:

lightsensorconnect

We connect the photo resistor to +5V (or +3.3V) on one end and the other end on a analog port (the ESP8266 has one, the Arduino has many). We also connect that same end to a resistor (in my diagram a 10K resistor) and the other end of the resistor to ground. What does this do? Well, current will flow from +5V over the photo resistor, continue over the 10K resistor and than to ground. What we are going to measure is the voltage at the point between the photo resistor and the normal resistor. Ohm’s law states V=IR, voltage is current times resistance. The current flowing from +5V to ground over both resistors will be the same (the amount of current does not change midway a circuit). That’s the key to figuring out the current at our analog port and here is how.

We can calculate the total current that flows from +5V to ground by adding the resistors and plugging it in Ohm’s law. Let’s say the photo resistor currently has a resistance of 10KΩ. The total resistance of the circuit is 10KΩ+10KΩ = 20KΩ. V = 5V which means I = 5V / 20KΩ = 0.25 mA. So we now know that there is 0.25 mA running through the circuit. Now we can calculate V at our analog input. The voltage drop over the photo resistor is V = IR and we now know I and R. V = 0.25 mA * 10KΩ = 2.5 V drop so at our analog input we will measure 5V – 2.5V = 2.5V. With 2 equal resistances, it makes sense that in the middle you will have 2.5V. Let’s take the next step.

The resistance of the photo resistor goes down when there is more light, so let’s make it a little darker, say 30KΩ. Let’s recalculate:

Total R = 30KΩ + 10KΩ = 40KΩ
I = 5V / 40KΩ = 0.125 mAVoltage drop over photo resistor = 0.125 mA * 30KΩ = 3.75 V
We measure 5V – 3.75V = 1.25V at our analog input

So less light means less voltage at our analog input. Well this math is all fine, but what does this mean? Well, if we know the voltage at our analog input we can also do the reverse and calculate the resistance of the photo resistor, just do the reverse.

Let me quickly share the setup and the code I used to test the resistors. You can my setup at the top. It is an Arduino Nano (which has 5 analog ports) and the 5 sensors, the bottom is the 5506 and moving up all the way to the 5539 at the top. It might be a bit hard to see. All black wires are +3.3V, all the white are ground and the different colors are for each of the analog inputs. You can see that I followed the schematic 5 times and importantly, used five 10KΩ resistors. You cannot combine all of them on one. Please do not forget to connect 3.3V to ARef which gives a better ready is my experience.

The code is simple, initialize five ports and continously display the results of the ports. I have added a header row every 10 rows so I can copy and paste that:

github-mark-32px Available on GitHub with more comment in the code. Direct download.

//
// The number of steps after which the header is repeated
//
#define STEPCOUNT 10
//
// The current step count
//
byte step = STEPCOUNT;

void setup() {
  //
  // Setup serial
  //
  Serial.begin(115200);
  Serial.println("Ready");
  //
  // Set the reference for measuring the analog signals
  // For some reason I got incorrect readings without connecting
  // the 3.3v (on my Arduino Nano) to AREF and setting this
  // reference
  analogReference(EXTERNAL);
  //
  // Setup all analog inputs. We are using 5 which is the maximum
  // for the Nano on which I tested.
  //
  pinMode(A0,INPUT);
  pinMode(A1,INPUT);
  pinMode(A2,INPUT);
  pinMode(A3,INPUT);
  pinMode(A4,INPUT);
}

void loop() {
  //
  // Increase our counter
  //
  step++;
  //
  // If we are over our STEPCOUNT then we repeat the header
  //
  if (step>STEPCOUNT) {
    //
    // The reference to the different photo resistors
    // GL5506, GL5516, GL5528, GL5537 and GL 5539
    //
    Serial.println("* 5506  5516  5528  5537  5539");
    step = 0;
  }
  //
  // Print all analog values to serial
  //
  Serial.print("  ");
  Serial.print(analogRead(A0));
  Serial.print("   ");
  Serial.print(analogRead(A1));
  Serial.print("   ");
  Serial.print(analogRead(A2));
  Serial.print("   ");
  Serial.print(analogRead(A3));
  Serial.print("   ");
  Serial.print(analogRead(A4));
  Serial.println();
  delay(250);
}

If we take the values it shows during daylight, inside the house:

* 5506  5516  5528  5537  5539
  975   969   774   619   218
  975   968   773   619   220
  975   969   773   618   216
  975   968   771   616   215
  975   968   771   617   221
  975   969   774   620   226
  975   969   776   622   225
  976   969   775   621   221
  975   969   774   619   220
  975   969   774   619   219
  975   968   772   617   216

As you can see, the values are relatively stable. So let’s take one of the values of the 5528, 775. How do we calculate the resistance from that? The analog port has a 10 bit resolution, which means it can go from 0 to 1023. 1023 will be at 3.3V (in my case. If you use a Uno for example it will be 5V). The reading is 496 which means it is reading a voltage of 775/1023*3.3V = 2.5V. So we know the voltage drop was 3.3V-2.5V = 0.8V. So we know V. Now we need to know I and from that we can calculate R. We can calculate R because we know V and R for the other part of the setup, the 10KΩ. I = V/R = 2.5V / 10KΩ = 0.25 mA. Now we take that 0.25 mA and use it for calculating the resistance of the photo resistor.
R = V/I = 0.8V / 0.25 mA = 3,200 Ω. Now you can go to the GL5528 datasheet and see

gl5528

that the amount of light is between 30 and 85 lux. Well, that’s quite a broad range and not really useful for calculating the amount of lux but the deviation of these sensors might vary piece to piece but do not vary that much per piece, so if your sample decides to be more towards the dark side, it will be there with higher or lower light settings as well. What this means is that the sensors are great for detecting deltas in light even though getting a precise lux reading is not really feasible. Ok, well than we need more readings:

light from a normal bulb:
* 5506  5516  5528  5537  5539
  974   967   739   623   279
  982   981   844   717   437
  992   988   870   751   454
  994   991   874   758   440
  995   991   873   752   325
  992   986   836   700   137
  985   979   795   654   62
  978   972   754   610   34
  971   969   792   668   379
  988   985   854   727   440
  993   990   871   749   440

light from a mobile phone
* 5506  5516  5528  5537  5539
  1006   1007   956   925   795
  1006   1007   956   925   796
  1006   1007   956   925   797
  1006   1007   956   925   797
  1006   1007   956   926   798
  1006   1007   955   925   795
  1006   1007   956   925   796
  1005   1007   955   924   795
  1006   1007   955   924   793
  1005   1007   955   925   796
  1005   1007   955   925   795

light at dusk
* 5506  5516  5528  5537  5539
  834   834   385   208   20
  840   838   394   216   22
  840   840   402   222   23
  840   840   405   225   24
  839   839   404   225   24
  839   838   404   224   23
  840   838   405   225   24
  841   839   405   226   24
  841   839   405   226   24
  844   840   406   227   24
  845   840   406   227   24

light in the evening
* 5506  5516  5528  5537  5539
  582   583   118   52   1
  581   582   118   52   1
  580   583   118   53   1
  580   582   118   52   1
  580   581   118   52   1
  578   580   117   52   1
  577   577   116   52   1
  565   561   109   49   1
  584   583   118   51   1
  586   587   120   53   1
  589   590   121   53   1

There are a few things to notice. First, I thought it was interesting to see that the values fluctuated with a normal bulb. This sample was not an incident, it was doing that the whole time. I think it might have to do with the fact that light bulbs fluctuate because of the way the alternating current alternates but I’m not sure. The second thing to notice is that the 5506 does not really vary that much with light, especially compared to the others. It’s not because it’s broken, but it’s because it’s resistance is small compared to the 10kΩ resistor which means it does not leave a lot of ‘bandwidth’ to show it’s capabilities.

Maybe I will do some more readings where I take a resistor to match each photo resistor and see what the results are than.

ESP8266 & WS2812

ESP8266 & WS2812

I managed to get the ESP and the WS2812 individually configurable LEDs to play nice to each other and coded the ESP through the Arduino IDE. The final setup which I used, I thought I had tried before but somehow I didn’t apparently. So what worked for me is the following technical setup:

A 5V to 3.3V converter with a USB feed to my laptop, +5V to +5V and GND to GND. Next connect the 3.3V of the converter to 5V of the WS2812 and GND of the 3.3V end to the GND of the WS2812 led strip (or circle in my case) and connect the same GND to the GND of your ESP. I have it now working with a NodeMCU v1 and a Wemos D1 Mini. The DI pin (data in) of the WS2812 goes to pin D4 which is GPIO2.

For the library you need the Adafruit Neopixel library which you can download here. The example code should work (check to make sure you select the right pin).

github-mark-32px Available on GitHub with more comment in the code. Direct download.

You can also try my example which is a running yellow strip of light:

//
// The library from Adafruit which enables the use of the WS2812
// or NeoPixel
//
#include <Adafruit_NeoPixel.h>

//
// The pin the circle of WS2812 leds is connected to
//
#define CIRCLEPIN 2
//
// The number of leds in our circle
//
#define PIXELCOUNT 12

//
// Initialize the Adafruit library
//
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT,CIRCLEPIN,
  NEO_GRB+NEO_KHZ800);

//
// The number of leds lit
//
byte maxLed = 1;
//
// Is the number of leds increasing or decreasing
//
int direction = 1;

void setup() {
  //
  // Start the led string and turn them all off
  //
  pixels.begin();
  for(byte i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
}

void loop() {
  //
  // Turn the first 'maxLed' leds yellow
  //
  for(byte i=0;i<maxLed;i++){
    pixels.setPixelColor(i, pixels.Color(55,42,0));
  }
  //
  // Set the remaining leds black
  //
  for(byte i=maxLed;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  //
  // Don't forget to call the pixels.show();
  //
  pixels.show();
  delay(100);
  //
  // Determine the next step in number of leds to show
  //
  maxLed = maxLed+direction;
  if (maxLed<1 || maxLed>PIXELCOUNT) {
    direction = -direction;
    maxLed = maxLed+direction;
  }
}

A very basic example but I was very happy that it worked.

Theoratically speaking, you should be able to run this from other pins and with a small number of leds, maybe even without a seperate power source. I also still want to try to run it at 5v and use a logical converter for the DI pin. If I manage to do this, I will share this.

Fun with HC-SR04 and WS2812

Fun with HC-SR04 and WS2812

After I managed to get the distance sensor HC-SR04 working and got the LED circle based on WS2812 working, I felt it was time to combine them in a fun project.

I connected two LED circles, 16 LEDs and 12 LEDs where the DO of the 16 went into the DI of the 12. What I wanted to do is in the outer circle have a red circle run in circles where the speed was dependant on the distance of an object in front of the sensor. The closer the object, the faster it moves. The inner circle shows the distance to the object. The farther the object, the more LEDs would light up.

github-mark-32px Available on GitHub with more comment in the code. Direct download.

The code for the Arduino IDE:

//
// The library from Adafruit which enables the use of the WS2812
// or NeoPixel
//
#include <Adafruit_NeoPixel.h>

//
// The pin the circle of WS2812 leds is connected to
//
#define CIRCLEPIN 6
//
// The number of leds in our two circles (12+16)
//
#define PIXELCOUNT 28

//
// Initialize the Adafruit library
//
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT,CIRCLEPIN,
  NEO_GRB+NEO_KHZ800);

//
// The current position
//
int degree = 0;

//
// The trigger and echo pin for the HC-SR04
//
#define TRIGGERPIN 13
#define ECHOPIN 12

//
// How long we delay before the next read and update of the leds
//
int delayMove = 50;

void setup() {
  //
  // Start the led string and turn them all off
  //
  pixels.begin();
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
  //
  // Prepare the HC-SR04 pins
  //
  pinMode(TRIGGERPIN, OUTPUT);
  pinMode(ECHOPIN, INPUT);
}

void loop() {
  //
  // Determine the distance between object and HC-SR04
  // Read about it in more detail on
  // https://piandmore.wordpress.com/2016/10/04/arduino-hc-sr04-ultrasonic-distance/
  //
  long duration, distanceCM;
  digitalWrite(TRIGGERPIN, LOW);
  delayMicroseconds(5);
  digitalWrite(TRIGGERPIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGERPIN, LOW);
  duration = pulseIn(ECHOPIN, HIGH);
  //
  // The distance in cms
  //
  distanceCM = (duration/2) / 29.1;
  //
  // Turn all pixels off
  //
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  //
  // Turn on the inner circle leds
  // 1 led for every 2 cm of distance
  //
  for (int i=16;i<16+distanceCM/2;i++) {
    pixels.setPixelColor(i, pixels.Color(0,50,0));
  }
  //
  // Determine the current position led of the outer circle
  // and turn on the required leds
  //
  int thisPixel = (degree*16)/360;
  pixels.setPixelColor((thisPixel+3)%16,pixels.Color(255,0,0));
  pixels.setPixelColor((thisPixel+2)%16,pixels.Color(100,0,0));
  pixels.setPixelColor((thisPixel+1)%16,pixels.Color(40,0,0));
  pixels.setPixelColor((thisPixel)%16,pixels.Color(15,0,0));
  pixels.show();
  //
  // Depending on the distance of an object, make the circle move
  // faster (if it is closer) or slower (if it is farther away)
  // and take the maximum time of it is very far away or
  // if there is no object
  //
  if (distanceCM>=200) {
    delayMove = 200;
  } else {
    delayMove = distanceCM;
  }
  delay(delayMove);
  degree += 10;
  if (degree>=360) {
    degree -= 360;
  }
}

The code looks a lot like the two earlier mentioned codes combined. What is added is the 12 LEDs which, as you can see, are addressed as being the next 12 on the same string as the 16.

Arduino & WS2812

Arduino & WS2812

The WS2812 is an RGB led with a controller built in. More importantly, the built in controller allows for concatenation of the leds and you supply the colors on a bus and each led ‘takes’ one color and passes the rest on. You can buy these as a long string or in various shapes. In this example, I have a 16 led circle.

Connecting the circle is done with four wires, GND to GND, VCC to 5V (please note it is 5 Volts and not 3.3 Volts). There is also a DI and a DO, Data In and Data Out. You connect the DI pin to a pin on your Arduino. In my example, it is pin 6.

The library you need can be found here. Like most Arduino IDE libraries, you install it by going to the menus Sketch, Include Library, Add .ZIP Library. Don’t forget to close all instances of Arduino IDE and restart.

github-mark-32px Available on GitHub with more comment in the code. Direct download.

Let’s first look at the code:

//
// The library from Adafruit which enables the use of the WS2812
// or NeoPixel
//
#include <Adafruit_NeoPixel.h>

//
// The pin the circle of WS2812 leds is connected to
//
#define CIRCLEPIN 6
//
// The number of leds in our circle
//
#define PIXELCOUNT 16

//
// Initialize the Adafruit library
//
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT,CIRCLEPIN,
  NEO_GRB+NEO_KHZ800);

//
// The current position in degrees
//
int degree = 0;

void setup() {
  Serial.begin(115200);
  //
  // Start the led string and turn them all off
  //
  pixels.begin();
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
}

void loop() {
  Serial.println(degree);
  //
  // Turn all leds to black
  //
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  //
  // Convert degrees to the pixel position
  //
  int thisPixel = (degree*PIXELCOUNT)/360;
  //
  // Set the pixels with a trailing tail
  //
  pixels.setPixelColor((thisPixel+3)%16,pixels.Color(255,0,0));
  pixels.setPixelColor((thisPixel+2)%16,pixels.Color(100,0,0));
  pixels.setPixelColor((thisPixel+1)%16,pixels.Color(40,0,0));
  pixels.setPixelColor((thisPixel)%16,pixels.Color(15,0,0));
  //
  // Don't forget to call the pixels.show();
  //
  pixels.show();
  delay(50);
  degree += 10;
  if (degree>=360) {
    degree -= 360;
  }
}

In the setup function, we call pixels.begin() to start initialize. Every time we call pixels.show the data is send to the LEDs. With setPixelColor you set the color for each pixel.

So what this code does is make a red light go around in circles followed by a small fading trail.

With regards to the code, I know it would have made more sense to just use the pixel counter instead of degrees, especially since 360 degrees into 16 LEDs means an increase of 22.5.

Also, you do not need to set every color back to black because it remembers the last color. Taking all this into account, the smaller version of the code will be:

//
// The library from Adafruit which enables the use of the WS2812
// or NeoPixel
//
#include <Adafruit_NeoPixel.h>

//
// The pin the circle of WS2812 leds is connected to
//
#define CIRCLEPIN 6
//
// The number of leds in our circle
//
#define PIXELCOUNT 16

//
// Initialize the Adafruit library
//
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT,CIRCLEPIN,
  NEO_GRB+NEO_KHZ800);

//
// The current pixel
//
byte thisPixel = 0;

void setup() {
  //
  // Start the led string and turn them all off
  //
  pixels.begin();
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
}

void loop() {
  //
  // Set the pixels with a trailing tail
  // Since we paint the last pixel black, we do not need to initialize
  // all pixels to black
  //
  pixels.setPixelColor((thisPixel+4)%16,pixels.Color(255,0,0));
  pixels.setPixelColor((thisPixel+3)%16,pixels.Color(100,0,0));
  pixels.setPixelColor((thisPixel+2)%16,pixels.Color(40,0,0));
  pixels.setPixelColor((thisPixel+1)%16,pixels.Color(15,0,0));
  pixels.setPixelColor((thisPixel)%16,pixels.Color(0,0,0));
  //
  // Don't forget to call the pixels.show();
  //
  pixels.show();
  delay(30);
  thisPixel++;
  if (thisPixel>16) {
    thisPixel = 0;
  }
}
Arduino  & HC-SR04 ultrasonic distance

Arduino & HC-SR04 ultrasonic distance

A very fun sensor is the HC-SR04 ultrasonic distance sensor. It’s fun because it is quite a good sensor and fun to play with and of course it looks like it’s a pair of eyes looking at you.

When connecting the sensor, you need to connect 4 pins, GND to GND, VCC to 5V (if you connect it to a 3.3V power supply, it won’t work), a trigger pin and an echo pin.

In the example below in the Arduino IDE, I have used 13 as the trigger pin and 12 as the echo pin.

github-mark-32px Available on GitHub with more comment in the code. Direct download.

//
// The HC-SR04 requires two pins, one to trigger a reading (TRIGGERPIN)
// and one to measure the distance (ECHOPIN)
//
#define TRIGGERPIN 13
#define ECHOPIN 12

void setup() {
  //
  // Intialize serial
  //
  Serial.begin (115200);
  //
  // The TRIGGERPIN will be an output
  //
  pinMode(TRIGGERPIN,OUTPUT);
  //
  // The ECHOPIN will be an input
  //
  pinMode(ECHOPIN,INPUT);
}

void loop() {
  //
  // The duration will contain the time in microseconds that the echo takes
  // to return. The distance will contain the distance in cms
  //
  long duration, distance;
  //
  // To tell the HC-SR04 to start a reading, we should put the TRIGGERPIN
  // high for 10 microseconds, so we pull it LOW, than HIGH for 10 microseconds
  // and LOW again. Immediately after we check how long the ECHOPIN is HIGH
  //
  digitalWrite(TRIGGERPIN,LOW);
  delayMicroseconds(5);
  digitalWrite(TRIGGERPIN,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGERPIN,LOW);
  duration = pulseIn(ECHOPIN,HIGH);
  //
  // The distance travelled by the sound send out is duration divided by the
  // pace of sound which is 29.1 ms/cm. We divide by 29.1 to get the amount
  // of centimeters and we divide by two because the sound travel to the object
  // and back, so the distance to the object is half the distance traveled
  // by the sound.
  //
  distance = (duration/2)/29.1;
  if (distance>=200 || distance<=0){
    Serial.println("Out of range");
  } else {
    Serial.print(distance);
    Serial.println(" cm");
  }
  delay(100);
}

To trigger a distance reading, you have to set the trigger pin high for 10 milliseconds. What I have done in the example above is take the trigger pin low for 5 ms, that bring it high for 10 ms and bring it back low again. Theoratically speaking, you should not need the first digitalWrite(TRIGGERPIN,LOW) but it’s there to make sure the pin is low.

Next we read the time the ECHOPIN stays HIGH (so it goes from LOW to HIGH, than stays at HIGH depending on the time it takes for the echo to return). We take that duration and divide it by 2 and than by 29.1. We divide by 29.1 because that is the pace of sound (which is 1 / speed of sound) in dry air. So we are saying that for every 29.1 ms sound travels 1 cm. We divide by two because the distance calculated is the distance from our sensor to the object and back to the sensor.

Arduino & ESP and DS18B20

Arduino & ESP and DS18B20

I did an article before on the DS18B20 and the NodeMCU. That article was based on LUA. In this article I will explain how to get this to work in the Arduino IDE. For connecting the DS18B20, please follow the instructions in the previous article. Next we need to get the libraries. There are two you need:

You install both of these libraries by selecting the following menu options in Arduino IDE: Sketch, Include Library, Add .ZIP Library.

For some reason, the Dallas temperature has a rather strange name. If you wish, you can rename the directory from Arduino-Temperature-Control-Library to DallasTemperature. That’s what I did. (If you wish to do that, go to the library location of Arduino, usually something like ….\My Documents\Arduino\libaries on Windows and just rename the directory as you would any directory).

Please remember to restart Arduino IDE.

The code is, with the usage of the libraries, quite simple:

#include <OneWire.h>
#include <DallasTemperature.h>

#define DS18B20BUS 0
OneWire oneWire(DS18B20BUS);
DallasTemperature DS18B20(&oneWire);

char temperatureCString[6];
char temperatureFString[6];

void setup() {
  Serial.begin(115200);
  Serial.println("Ready to read temperature:");
  DS18B20.begin();
}

void getTemperature() {
  float tempC;
  float tempF;
  do {
    DS18B20.requestTemperatures(); 
    tempC = DS18B20.getTempCByIndex(0);
    dtostrf(tempC,2,2,temperatureCString);
    tempF = DS18B20.getTempFByIndex(0);
    dtostrf(tempF,3,2,temperatureFString);
    delay(100);
  } while (tempC==85.0 || tempC==(-127.0));
}

void loop() {
  getTemperature();
  Serial.print("Temperature in Celsius: ");
  Serial.println(temperatureCString);
  Serial.print("Temperature in Fahrenheit: ");
  Serial.println(temperatureFString);
  delay(300);
}

 

Arduino & OLED display

Arduino & OLED display

A while back I bought an OLED display on AliExpress. It’s yellow and blue and 128×64. The nice thing was that it was based on I2C protocol so I thought I would get it working on my ESP but I couldn’t.

Now with the Arduino‘s, I thought I would give it another try and it turns out te be quite easy. Connecting the OLED to the Arduino requires four wires. GND goes to GND, VCC goes to 3.3V, SCL goes to A5 and finally SDA goes to A4.

Next you need a library of course. In this case it is called u8glib and you can download it on github (the downloadlink for the Arduino library is in the text if you scroll down). Install it in the Arduino IDE using the menus Sketch, Include Library, Add .ZIP Library. That’s it. You are ready to experiment.

The library comes with a lot of examples, but let’s start out with Hello World!

#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

int offset;

void draw() {
  u8g.setFont(u8g_font_unifont);
  u8g.drawStr(0,10+offset,"Hello World!");
}

void setup() {
  offset = 0;
}

void loop() {
  u8g.firstPage();  
  do {
     draw();
  } while(u8g.nextPage());
  delay(50);
  offset++;
  if (offset>50) {
    offset = 0;
  }
}

In the loop function, you have to have the u8g.firstPage() and the loop with draw() until u8g.nextPage() is false. You put your ‘art’ in the draw() function. The loop is needed because the display is written to in sections. You don’t have to worry how. This is what the loop does for you.

The u8g library is very extensive and very well documented. All functions can be found in the reference. I suggest trying some things yourself.

Supported devices

Arduino, OLED LCD & 4 sensors

Arduino, OLED LCD & 4 sensors

After describing four sensors, the SI7021, TLS2561, BH1750 and the BMP180, I wanted to see if I could combine all of these on one bus and display information on an OLED screen, also I2C.

In short, it is very possible and it is combining the different code to read the sensors and than creating some lines to display on the OLED screen.

combiningi2c-1

github-mark-32px Available on GitHub with more comment in the code. Direct download.

Since the code is not that difficult, I will share it here and in a later stage, describe it in more detail:

//
// LCD
//
#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

//
// SI7021
//
#include <Wire.h>
#include <SI7021.h>

#if defined(ESP8266)
//
// For the ESP8266 we need these to be defined for I2C
//
#define SDA 4
#define SCL 5
#endif

SI7021 sensor;

float temperature;
int humidity;

//
// TSL2561
//
#include "TSL2561.h"

TSL2561 tsl(TSL2561_ADDR_FLOAT); 

boolean hasTSL = false;
uint16_t lux1;

//
// BH1750
//
#include <BH1750.h>

BH1750 lightMeter;

uint16_t lux2;

//
// BMP180
//
#include <SFE_BMP180.h>
#define ALTITUDE 0

SFE_BMP180 pressure;

boolean hasBMP = false;
double temperature2,pressure2,altitude2;

//
// LCD, the function that is called to draw to the OLED
//
void draw() {
  //
  // Set the correct values for drawing with the u8g library
  //
  u8g.setFont(u8g_font_6x10);
  u8g.setFontRefHeightExtendedText();
  u8g.setDefaultForegroundColor();
  u8g.setFontPosTop();
  char printThis[14];
  String t;
  //
  // Temperature from SI7021 and if we have it
  // the BMP180 (which is than averaged)
  //
  float tmp2 = temperature;
  if (hasBMP) {
    tmp2 = (tmp2+temperature2)/2;
  }
  t = "Temp:";
  t.toCharArray(printThis,13);
  u8g.drawStr(0,0,printThis);
  //
  // The temperature with degrees and C added
  //
  t = String(tmp2,1)+" "+(char)176+"C";
  t.toCharArray(printThis,13);
  u8g.drawStr(50,0,printThis);
  //
  // Humidity from the SI7021
  //
  t = "Humi:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,11,printThis);
  //
  // The humidity and % added
  //
  t = String(humidity)+" %";
  t.toCharArray(printThis,14);
  u8g.drawStr(50,11,printThis);
  //
  // The lux from the BH1750 and from the
  // TSL2561 if we have it (it is averaged if we have it)
  //
  t = "Lux:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,22,printThis);
  uint16_t tmp = lux2;
  if (hasTSL) {
    tmp = (tmp+lux1)/2;
  }
  //
  // The lux with lx added
  //
  t = String(tmp)+" lx";
  t.toCharArray(printThis,8);
  u8g.drawStr(50,22,printThis);
  //
  // The pressure from the BMP180
  //
  t = "Press:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,33,printThis);
  //
  // The pressure with mb added
  //
  t = String(pressure2,0)+" mb";
  t.toCharArray(printThis,14);
  u8g.drawStr(50,33,printThis);
  //
  // The altitude from BMP180
  //
  t = "Alti:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,44,printThis);
  //
  // The altitude with m added
  //
  t = String(altitude2,0)+" m";
  t.toCharArray(printThis,14);
  u8g.drawStr(50,44,printThis);
}

void setup() {
  //
  // I2C startup
  //
#if defined(ESP8266)
  //
  // For the ESP8266 we need to start the sensor with SDA and SCL pin numbers
  //
  sensor.begin(SDA,SCL);
#else
  //
  // For Arduino we can just call begin.
  //
  sensor.begin();
#endif
  //
  // SI7021
  //
  temperature = 0;
  humidity = 0;
  
  //
  // TSL2561
  //
  if (tsl.begin()) {
    hasTSL = true;
    tsl.setGain(TSL2561_GAIN_16X);
    tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS);
  }

  //
  // BH1750
  //
  lightMeter.begin();
  //
  // BMP180
  //
  if (pressure.begin()) {
    hasBMP = true;
  }
}

void loop() {
  //
  // LCD, the draw routine is handled by the u8g library
  //
  u8g.firstPage();  
  do {
     draw();
  } while(u8g.nextPage());

  //
  // SI7021
  //
  temperature = sensor.getCelsiusHundredths();
  temperature = temperature / 100;
  humidity = sensor.getHumidityPercent();

  //
  // TSL2561
  //
  if (hasTSL) {
    uint32_t lum = tsl.getFullLuminosity();
    uint16_t ir, full;
    ir = lum >> 16;
    full = lum & 0xFFFF;
    lux1 = tsl.calculateLux(full, ir);
  }

  //
  // BH1750
  //
  lux2 = lightMeter.readLightLevel();

  //
  // BMP180
  //
  if (hasBMP) {
    char status;
    status = pressure.startTemperature();
    if (status != 0) {
      delay(status);
      status = pressure.getTemperature(temperature2);
      if (status != 0) {
        status = pressure.startPressure(3);
        if (status != 0) {
          delay(status);
          status = pressure.getPressure(pressure2,temperature2);
          if (status != 0) {
            double p0 = pressure.sealevel(pressure2,ALTITUDE);
            altitude2 = pressure.altitude(pressure2,p0);
          }
        }
      }
    }
  }
  
  delay(50);
}

If you have any questions/remarks, feel free to post them below.

Arduino or ESP & BH1750 light sensor

Arduino or ESP & BH1750 light sensor

One of the sensors I bought is a BH1750 (on the print it looks like BHI750, but it’s not an I but a 1) light sensor which measures the available light and has an I2C interface.

Again, getting this to work is not that hard. First you need to download the BHI1750 Library

which you add to Arduino IDE with Sketch, Include Library, Add .ZIP Library and select your file. The library comes with an example. In my case the file was called BH1750Test.pde. My computer did not have an association set up for .pde but if you change it to .ino it will work.

I have tested this code with an Arduino Nano and an ESP8266 and both worked. If you want to connect it to another Arduino or are going to use a seperate power source, please make sure you do not supply it with more than 4.5 volts as that is it’s maximum input power.

A copy of the example code:

/*

Example of BH1750 library usage.

This example initalises the BH1750 object using the default
high resolution mode and then makes a light level reading every second.

Connection:
 VCC-5v
 GND-GND
 SCL-SCL(analog pin 5)
 SDA-SDA(analog pin 4)
 ADD-NC or GND

*/

#include 
#include 


BH1750 lightMeter;


void setup(){
  Serial.begin(9600);
  lightMeter.begin();
  Serial.println("Running...");
}


void loop() {
  uint16_t lux = lightMeter.readLightLevel();
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lx");
  delay(1000);
}

It’s amazingly short.

As you will have seen, the sensor has five pins while we need four for I2C. The fifth pin is called addr:

bh1750back

and this can be used to set the I2C address of the sensor. Floating or connected to GND, the I2C address will be 0x23 which is also the default in the library. If you connect it to VCC the address will be 0x5C and you will have to modify the library (unfortunately). I am working on suggesting an update to this library.