Showing posts with label Mailbag. Show all posts
Showing posts with label Mailbag. Show all posts

Wednesday, July 27, 2016

Mailbag - BH1750FVI - I2C Light Sensor Driver




//YOUTUBE VIDEO WILL FOLLOW HERE //

   In the process of choosing of some Light Sensors for one of the new projects that will involve the nEXT EVO Board and also the MPDMv4 Mains Dimmer  somebody suggested to give a try also to the ROHM BH1750FVI Sensor.

Just received some BH1750FVI modules in my mail yesterday and must say that it's a pretty impressive little board for only about 2.5USD, even less in a pack of 10!

This is how are looking the received modules:

BH1750FVI Module - TOP

   As you can see on the picture above, on the tiny board, you have the BH1750FVI Sensor, a LDO regulator some filtering caps and pull-up resistors and that's it!



 
BH1750FVI Module - Bottom
     The bottom side is bringing us more good news, the Module interface connector is fully compatible with the nEXT EVO  Bus!



BH1750FVI Overview

  BH1750FVI is an digital Ambient Light Sensor IC for I2C bus interface. This IC is the mostly used to obtain the ambient light data for adjusting LCD and Keypad backlight power of Mobile phone. 
 This is great as we are looking forward to use it for Automatic light adjustment using the MPDMv4 AC Dimmer board :)





Features

  • I2C bus Interface ( f / s Mode Support )
  • Spectral responsibility is approximately human eye response
  • Illuminance to Digital Converter
  • Wide range and High resolution. ( 1 - 65535 lx )
  • Low Current by power down function
  • 50Hz / 60Hz Light noise reject-function
  • 1.8V Logic input interface
  • Native 3.3V Device
  • No need any external parts
  • Light source dependency is little. ( ex. Incandescent Lamp. Fluorescent Lamp. Halogen Lamp. White LED. Sun Light )
  • It is possible to select 2 type of I2C slave-address.
  • Adjustable measurement result for influence of optical window ( It is possible to detect min. 0.11 lx, max. 100000 lx by using this function. )
  • Small measurement variation (+/- 20%)
  • The influence of infrared is very small.


Internal Diagram
BH1750FVI - Internal Diagram

  • PD - Photo diode with approximately human eye response.
  • AMP - Integration-OPAMP for converting from PD current to Voltage.
  • ADC - AD converter for obtainment Digital 16bit data.
  • Logic + I2C Interface :
                 - Ambient Light Calculation and I2C BUS Interface. It is including below register.
                 - Data Register - This is for registration of Ambient Light Data. Initial Value is
                       "0000_0000_0000_0000".
                 - Measurement Time Register - This is for registration of measurement time. Initial Value
                          is  "0100_0101".
  • OSC - Internal Oscillator ( typ. 320kHz ). It is CLK for internal logic.

For more details please take a look at the BH1750FVI Datasheet.



What we will need:

    Connection with the ESP8266 nEXT EVO Board is very easy, as MPU6050 GY-521 Module connector is fully compatible with the nEXT Bus connector. Depending on how to you choose you socket type, you can install it on TOP or Bottom of the ESP8266 nEXT EVO Board :


BH1750FVI Module directly connected to the ESP8266 nEXT EVO Board







BH1750FVI Driver implementation


1. Init I2C bus/interface


 Standard I2C Bus Initialisation function:

function init_I2C()
    i2c.setup(bus, sda, scl, i2c.SLOW)
end



2. WRITE Function - Set BH1750FVI Register config

      From BH1750FVI Datasheet :
   

  • No active state : pwr_down 0x00 
  • Wating for measurment command : pwr_on=0x01 
  • Reset data register value - not accepted in POWER_DOWN mode : reset=0x07

    Continuous modes, no pwr down:
  •  Start measurement at 1lx resolution. Measurement time is approx 120ms:
            hi_res_m1=0x10 
  • Start measurement at 0.5lx resolution. Measurement time is approx 120ms. 
           hi_res_m2=0x11
  • Start measurement at 4lx resolution. Measurement time is approx 16ms.
           lo_res_m1=0x13


    Device is automatically set to Power Down after measurement:
  • Start measurement at 1lx resolution. Measurement time is approx 120ms.
          hi_res_m3=0x20
  • Start measurement at 0.5lx resolution. Measurement time is approx 120ms.
           hi_res_m4=0x21
  • Start measurement at 1lx resolution. Measurement time is approx 120ms.
          lo_res_m2=0x23
 

function setcfg(cfg) 
    i2c.start(id)
    i2c.address(id, dev_addr ,i2c.TRANSMITTER)
    i2c.write(id,cfg)
    i2c.stop(id)
end


3. READ Sensor Input Function


Measurement Procedure

function read_input(dev_addr)
      i2c.start(id)
      i2c.address(id, dev_addr,i2c.RECEIVER)
      c = i2c.read(id,2)
      i2c.stop(id)
      --print("RAW H: "..string.byte(c,1))
      --print("RAW L: "..string.byte(c,2))
      rawl = (bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2))
      lux = rawl/1.2
      print(string.format("\nLight Level: %0.2f lux",lux))
      --print(string.format("             %d raw",rawl))
      return rawl
end


4. MAIN PROGRAM


id = 0                    --I2C Bus ID
sda=2                     --GPIO4
scl=1                      --GPIO5
dev_addr = 0x23   --BH1750FVI I2C Address
i2c_init()                          --init I2C Bus
setcfg(hi_res_m1)            --SET config register
read_input(dev_addr)     --Read sensor data and compute LUX Light level value





Thursday, March 31, 2016

Mailbag - Si7021 / SHT21 Temperature/Humidity sensor








And the story behind: 

Somebody sent to me a nice & tiny temperature/humidity sensor breakout board based on the Si7021 IC:

Si7021 Module - Top View

On the Top side we have Si7021 Sensor only.


Si7021 Module - Bottom View

Bottom Side, a 3.3V LDO and a Voltage level shifting circuit that probably makes it 5V tolerant on I2C bus. We will use it at 3.3V so nothing to worry about.



DESCRIPTION

    The  Si7021  I2C  Humidity  and  Temperature  Sensor  is  a  monolithic  CMOS  IC integrating   humidity   and   temperature   sensor   elements,   an   analog-to-digital converter, signal processing, calibration data, and an I2C Interface.

    The patented use of industry-standard, low-K polymeric dielectrics for sensing humidity enables the  construction  of  low-power,  monolithic  CMOS  Sensor  ICs  with  low  drift  and hysteresis, and excellent long term stability.

   The  humidity  and  temperature  sensors  are  factory-calibrated  and  the  calibration data is stored in the on-chip non-volatile memory.  This ensures that the sensors are fully interchangeable, with no recalibration or software changes required.

   The Si7021 offers an accurate, low-power, factory-calibrated digital solution ideal for measuring humidity, dew-point, and temperature, in applications ranging from HVAC/R and asset tracking to industrial and consumer platforms.


Si7021 - Block Diagram


Nice. Looks more or less like SHT21 from Sensirion. And we will see that it is quite compatible (at least on the temp/humidity reading procedure side) with small differences for the rest of registers.




FEATURES
  • Precision Relative Humidity Sensor - ± 3% RH (max), 0–80% RH
  • High Accuracy Temperature Sensor - ±0.4 °C (max), –10 to 85 °C
  • 0 to 100% RH operating range
  • Up to –40 to +125 °C operating range
  • Wide operating voltage (1.9 to 3.6 V) (SHT21 - 2.1V min !)
  • Low Power Consumption:
         - 150 μA active current
         - 60 nA standby current
  • Factory-calibrated 
  • I2C Interface
  • Integrated on-chip heater
  • 3x3 mm DFN Package
  • Excellent long term stability
  • Optional factory-installed cover
        - Low-profile
        - Protection during reflow
        - Excludes liquids and particulates



Si7021 - Pinout Diagram



Typical Application Circuit for Relative Humidity and Temperature Measurements




For more details please take a look at the Si7021 Datasheet.



What we will need:

  • ESP8266 nEXT EVO Board
  • Si7021 Module as the one from above
  • For programming and uploading the driver and the software we will continue to use the LuaUploader as before.  
Connection with ESP8266 nEXT EVO Board is pretty straight-forward as the module is fully pin-to-pin compatible with the availavble nEXT Bus connector.

 
Si7021 Board connected with ESP8266 nEXT EVO DevBoard - TOP view




Si7021 Board connected with ESP8266 nEXT EVO DevBoard - 45 deg view





Software implementation

 The Si7021 communicates with the host controller over a digital I2C interface. The 7-bit base slave address is 0x40

 Master I2C devices communicate with the Si7021 using a command structure. The commands are listed below in the I2C command  table.  
 Commands  other  than  those  documented  below  are  undefined  and  should  not  be  sent  to  the device.


 
I2C Command Table



Issuing a Measurement Command
 
   The measurement commands instruct the Si7021 to perform one of two possible measurements: Relative Humidity or  Temperature. 

   The  procedure  to  issue  any  one  of  these  commands  is  identical.  While  the  measurement  is  in progress, the option of either clock stretching (Hold Master Mode) or Not Acknowledging read requests (No Hold Master  Mode)  is  available  to  indicate  to  the  master  that  the  measurement  is  in  progress. The  chosen  command code determines which mode is used.

   Optionally,  a  checksum  byte  can  be  returned  from  the  slave  for  use  in  checking  for  transmission  errors.  The checksum  byte  will  follow  the  least  significant  measurement  byte  if  it  is  acknowledged  by  the  master.  


   The checksum  byte  is  not  returned  if  the  master  “not  acknowledges”  the  least  significant  measurement  byte.  The checksum byte is calculated using a CRC generator polynomial of x^8+ x^5 + x^4 + 1, with an initialization of 0x00.

   The  checksum  byte  is  optional  after  initiating  an  RH  or  temperature  measurement  with  commands  0xE5,  0xF5,0xE3, and 0xF3. It is required for reading the electronic ID with commands 0xFA 0x0F and 0xFC 0xC9. 


  For all other commands, the checksum byte is not supported.









1. Init I2C bus/interface

 Standard I2C Bus Initialisation function:

function init_I2C()
    i2c.setup(bus, sda, scl, i2c.SLOW)
end

2.  Write Si7021 Register Function


    write_Si_Reg = function (dev_addr, set) 
          i2c.start(0x0)
          i2c.address(0x0, dev_addr ,i2c.TRANSMITTER)
          i2c.write(0x0,set)
          i2c.stop(0x0)
          tmr.delay(5000)
     end

 3.  Read Si7021 Register Function 


     read_Si_Reg = function (dev_addr)          
          i2c.start(0x0)
          i2c.address(0x0, dev_addr,i2c.RECEIVER)
          tmr.delay(5000)
          c = i2c.read(0x0,2)
          i2c.stop(0x0)

          rval = (bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2))
          status = bit.band(rval,3)    --save status bits
          rval = bit.band(rval,65532)  --clear status bits
          return rval, status
     end

 4. Measuring Relative Humidity
 

         Once  a  relative  humidity  measurement  has  been  made,  the  results  of  the  measurement  
     may  be  converted  to percent relative humidity by using the following expression:

             hum = -6.0+125.0/65536.0*rval

       A humidity measurement will always return XXXXXX10 in the LSB field -> Status bit = 1 -> 

     marking a Humidity measurement data.

function read_hum()
   write_Si_Reg(dev_addr, RHumidityHoldCmd)
   tmr.delay(10000)
   read_Si_Reg(dev_addr)       
   hum = -6.0+125.0/65536.0*rval
   print("\nStatus : "..status)
   print("Humidity : "..string.format("%.2f",hum).."%")
end

 

5. Measuring Temperature

   Each time a relative humidity measurement is made a temperature measurement is also made for the purposes of temperature  compensation  of  the  relative  humidity  measurement.  If  the  temperature  value  is  required,  it  can  be read  using  command  0xE0;  this  avoids  having  to  perform  a  second  temperature  measurement.  


   The  measure temperature  commands  0xE3  and  0xF3  will  perform  a  temperature  measurement  and  return  the  measurement value, command 0xE0 does not perform a measurement but returns the temperature value measured during the relative humidity measurement.
The checksum output is not available with the 0xE0 command.

The results of the temperature measurement may be converted to temperature in degrees Celsius (°C) using the following expression:


     temp = -46.85+175.72/65536.0*rval

  A temperature measurement will always return XXXXXX00 in the LSB field - Status bit = 0 -> marking a Temperature measurement data.


 function read_temp()
   write_Si_Reg(dev_addr, TempHoldCmd)
   read_Si_Reg(dev_addr)      
   temp = -46.85+175.72/65536.0*rval
   print("Status : "..status)
   print("Temperature : "..string.format("%.2f",temp).."C")
end


6. Main Program
init_I2C()

tmr.alarm( 0, 5000, 1, function()
    read_hum()
    read_temp()
end)




Thursday, August 20, 2015

Mailbag - ESP8266 Weather Station 433Mhz KN-WS400 hack




  Using a 433Mhz radio link the ESP8266 CBDB Dev Board module equipped with a DHT22 temperature/humidity sensor is uploading data directly to the Konig 433 mhz wireless station with hygro-thermometer [KN-WS400N] :





And the story behind:


As been working to a ESP DHT22 sensors array for a Environment data logging system I was thinking that it would be nice to have also a direct reading panel for the data. And because just received in my mailbox few days ago a KN-WS400 Weather station to be used for another project I said why do not to take a deeper look and see if we can use it also as a realtime data view panel for our DHT22 sensors.

As you can see from the picture below, it has a big and nice looking display (not the best quality or contrast in town but, hey, it's just a 40USD unit, nothing fancy):

KN-WS400 Weather station

   It has only temperature and humidity capabilities, but for our project is more than enough:).


     What is interesting about KN-WS400 is the fact that it can receive temperature and humidity data also from another 3 external sensors (but delivered in the box with only one!).
You can setup and choose between 3 different channels, each one allocated for a separate remote sensor unit.


Remote sensor


Reading remote temperature data on Channel 1


Channel setup is done very simple, choose your desired free channel from your remote sensor unit and reset the corresponding channel on the Weather station by pressing more than 10 sec the channel button.

External sensor CHannel setup and C/F scale option buttons


    So far so good. The idea is to try to use another 2 ESP DHT22 sensor units to send the temperature and humidity data directly to WS400 Weather station on the available channels. Or, why not, to replace them all 3 with the WIFI Web enabled ESP DHT22 smarter ones :)

   To do this, first of all we need to take a look at the transmission frequency to know what kind of receiver/transmitter to use with our ESP DHT22 Modules.
   As is written on the back of the unit, the KN-WS400 Weather station use for remote sensors communication the standard 433Mhz frequency, same as probably most of the zillions different types of cheap weather stations available around.

So now, as we know the frequency, next we need to see if we can have any luck in decoding the communication protocol.



What do we need:

   I will not insist to much on the wiring setup as it is a very simple one, just connect your simple  433mhz Receiver module to your Power supply Vcc , GND  and the Data pin to your used Oscilloscope channel probe.

   As soon as it is connected and you start changing the channel on the KN-WS400 sensor module by pressing the CH button from the back of the unit, you will see a data burst on your Oscilloscope. See also Youtube video from above.

Data burst received on 433Mhz from KN-WS400 remote sensor

As you can see from the captured data above, it looks like the unit is transmitting the data in 6 separate data bursts. Actually, when zoomed in we can see that is sending the same data 6 times.






At a deeper look at the received data stream we can see that:
  •  Each transmission consists of 6 repetitions of the same data.
  • They are separated by a long sync signal ("preamble") that’s about 4.5ms (3.8ms low + 0.7ms high)
  • We can suppose the bit patterns (they might be inverted sometime 1<->0 but is not the case of this sensor) as:
           -   Logic 1 (or 0) is about 2.6ms -> 1.9ms low + 0.7ms high
           -   Logic 0 (or 1) is about 1.7ms -> 1.0ms low + 0.7ms high



"Preamble" measurement



Logic "1" Measuremnt



Logic "0" measurement


  Based on the assumptions from above, let's try to "transcribe" the signal from the above:

      PRE10101011100100010000010111110011010100000PRExxxxPRExxx4PRE

   Before even thinking to try to decode the data we need to be able to identify where reside each data value in the stream. For this taskthat can become quite complicated or impossible some time, you can start using a very simple technique: just change only one variable at a time, in very small increments if possible and look after changes.

  The easiest one to do, is the Channel setup, as we have on the back of the sensor unit a switch for it.

Press the channel button and change Channel to 1,2 and 3.
Capture and take a look at the received data :

PRE10101011100100010000010111110011010100000PRExxxxPRExxx4PRE
PRE10101011101000010000010111110011010100000PRExxxxPRExxx4PRE
PRE10101011100000010000010111110011010100000PRExxxxPRExxx4PRE  

Ahaaa..have you seen it? :)

 Let's arrange the data in a more readable format: 

1010 1011 1001 0001 0000 0101 1111 0011 0101 0000
1010 1011 1010 0001 0000 0101 1111 0011 0101 0000
1010 1011 1000 0001 0000 0101 1111 0011 0101 0000

  Looking better? :)

  Now you can clearly see that the channel data (CH) is encoded on 2 bits in the 3rd column. Not bad at all. You know why? because despite the fact that you cannot find 2 Weather stations with the same exact data format they are quite similar and any existing information can help you a lot in the reduction of the complexity of the decoding process. 
 
  Let's make another assumption based on the info that we already have from other existing models, that the first 2 bits from column 3 to be the battery status ones. Usually they are coded in this way.

  Powering the sensor unit from an external lab PSU and reducing gradually the voltage until under normal working one the data obtained looks:

1010 1011 1001 0001 0000 0101 1111 0011 0101 0000
1010 1011 0101 0001 0000 0101 1111 0011 0101 0000
1010 1011 0001 0001 0000 0101 1111 0011 0101 0000

Where :

   "10" -> PWR GOOD
   "01" -> AVG
   "00" -> Replace battery


Nice. So, until now, we have identified the  Battery status and Channel ID.  Let's go further.


For temperature and humidity a common found coding technique is as follows:
  • Humidity is stored as low/high order nibbles. So you need to take the first 4 bits and tack them on the end of the next 4 bits. 11010101 becomes 01011101. 
  • Temperature is transmitted as 12 bits in 3x nibbles ranging from low to high nibbles. A fixed offset of 900 is applied to the temperature value so 0 degrees F = 900 and each degree F change is 10 decimal. Then the obtained value is divided by 10. And converted to degC. Confusing and painful stuff to find in a data stream.

Sounds complicated? Why are temperature and humidity data coded like that?
My personal opinion is that some specifications were created for the first designed one and now as these cheap weather stations has become such a mass product everybody is copying more or less the same design :)


If somebody really knows the true reason for such a coding, I will more than happy to know. Might be some good reasons behind that I'm missing. 


Let's see what's happening in our case. And before anything else, let's use the same technique, keeping all the data the same and change slowly Temperature only part:


Battery=2
Channel=2 
Humidity=29%

10101011 1001 0001 0011 1010 1111 0001 1101 0000 
10101011 1001 0001 0011 1001 1111 0001 1101 0000
10101011 1001 0001 0011 1000 1111 0001 1101 0000
10101011 1001 0001 0011 0111 1111 0001 1101 0000
10101011 1001 0001 0011 0101 1111 0001 1101 0000
10101011 1001 0001 0011 0100 1111 0001 1101 0000


Can you see the temperature data changing?

And you know what?
IT IS IN deg C already!!
If you don't believe me just convert the values in decimal and divide them by 10!

For this type of weather station is no more fancy Fahrenheit transformation voodoo thing. You can see it in clear above.


Then you know what? Let's try directly our luck also with Humidity values. We have a steady 29 above, let's find it:

10101011 1001 0001 0011 1010 1111 0001 1101 0000 
10101011 1001 0001 0011 1001 1111 0001 1101 0000
10101011 1001 0001 0011 1000 1111 0001 1101 0000
10101011 1001 0001 0011 0111 1111 0001 1101 0000
10101011 1001 0001 0011 0101 1111 0001 1101 0000
10101011 1001 0001 0011 0100 1111 0001 1101 0000


WOW! Now that was a nice surprise! All in clear, no more fancy calculations :)



So, what we have so far:

Unique ID   VBAT    CH     Temperature          ????       Humidity      0
10101011     10         01      0001 0011 1010     1111      0001 1101      0000


Puzzle is almost solved.

Only few things remained "undecoded" but believe me after capturing hundreds and hundreds of data streams it looks like de ID remains stable, same with the mysterious "1111" between Temperature and Humidity and the "0" from the end.

As it looks like there is no fancy Checksum algorithm involved or any special data stream identifier I think we can move further and design your own ESP DHT22 Module transmission program for direct data upload. And as you can see in the above Youtube video it was a success.



 
As soon as I cleaned it a little bit, the Part 2 will follow, with the full code description.


PS: I really hope that after reading this article the guys from Konig or who are doing the coding for this product will let it as it is because it has becoming the most desired cheap Wireless Weather Station around, believe me, they are selling like hotcakes :). Thank you Konig for such a nice surprise for all of us!

And to be clear: I am NOT afiliated in any way with Konig and the unit was not received from Konig. But if they want to thank me for opening a new market for their products I will not say no. lol.