AZ-ONEBoard in MicroPython - Teil 1 - Ein Luxmeter mit BH1750 - AZ-Delivery
This post is also available as PDF document.

Four years ago I had the Environment system called AZ-Envy tried out, with an ESP8266-12F, an MQ2 as a alleys and an SHT30 for recording temperature and relative humidity. The heating current thickness of the sensor was approx. 170mA at 5V. This results in an output of 850 MW! The energy supply was carried out via USB, but for programming you also needed a USB for TTL adapter.

A few days ago I learned about a successor version of the board. The AZ Onoboard comes back with an ESP8266 12F and now has real USB access with a CH340C. The board also has an optional connection for 5V, where the bus voltage also lies. In addition to the main board, the KIT also contains three breakout boards: a SHT30, a BH1750 (luxet meter) and a SGP30, the CO2, as well as the TVOC proportion (totally volatile organic compounds), i.e. fleeting organic compounds in the room air. The sensor contained in the SGP30 is smaller than the MQ2 and works at 1.8V with 48mA, which is just 86mw. The CO2 EQIUValent is measured in PPM (parts per million) and tvoc in ppb (parts per trillion).

The sensorboards, the chips of which are all controlled via the I2C bus, are infected via one of the socket strips on the AZ onboard. Other I2C bus modules, such as an OLED display, can of course also be connected to these socket strips. However, you have to use jumbling cables to adapt the pin assignment.


Figure 1: AZ-Eoneboard

Figure 1: AZ-Eoneboard

Today we will take the BH1750 light sensor and eliminate a weak point of the AZ onboard. What it is about, what you can do and how the BH1750 is addressed via Micropython, you can find out in this episode from the series

Micropython on the ESP32, ESP8266 and Raspberry Pi Pico

today

A luxmeter with the ESP8266

I selected the Luxmeter as the first post because the associated Micropython module is not as extensive. This makes it easier for beginners and remain room for the expansion of the board and the integration of an OLED display. What is needed?

The hardware

The usual board with the controller, here an ESP8266, is replaced by the AZ onboard.

1 AZ-EONboard Developmentboard including Extensionboards SHT30, BH1750 & SGP30
1 0.91 inch OLED I2C Display 128 x 32 pixels
1 Mini Breadboard 400 PIN with 4 current rails
1 Jumper Wire cable 3 x 40 pcs. 20 cm M2M / F2M / F2F each
optional Logic Analyzer
optional Luxmeters for calibration

The structure is so simple that a circuit diagram is superfluous. We simply put the breakout board with the BH1750 on one of the boxes in the controller board, as shown in Figure 2.

Figure 2: AZ-ONEBARD with BH1750

Figure 2: AZ-ONEBARD with BH1750

The software

For flashing and the programming of the ESP32:

Thonny or

µpycraft

Signal tracking:

Saleae Logic 2

Used firmware for the ESP8266:

V1.23.0 (2024-06-02).

The micropython programs for the project:

timeout.py: Non-blocking software timer

oled.py: OLED-API

SSD1306.PY: OLED hardware driver

bh1750.py: Hardware driver module

bh1750_test.py: Demo program

bh1750_kal.py: Program for calibrating the Lux values

Micropython - Language - Modules and Programs

To install Thonny you will find one here detailed instructions (English version). There is also a description of how that Micropython firmware (As of 18.06.2022) on the ESP chip burned becomes. Like you that Raspberry Pi Pico get ready for use, you will find here.

Micropython is an interpreter language. The main difference to the Arduino IDE, where you always flash entire programs, is that you only have to flash the Micropython firmware once on the ESP32 so that the controller understands micropython instructions. You can use Thonny, µpycraft or ESPTOOL.PY. For Thonny I have the process here described.

As soon as the firmware has flashed, you can easily talk to your controller in a dialogue, test individual commands and see the answer immediately without having to compile and transmit an entire program beforehand. That is exactly what bothers me on the Arduino IDE. You simply save an enormous time if you can check simple tests of the syntax and hardware to trying out and refining functions and entire program parts via the command line before knitting a program from it. For this purpose, I always like to create small test programs. As a kind of macro, they summarize recurring commands. Whole applications then develop from such program fragments.

Autostart

If the program is to start autonomously by switching on the controller, copy the program text into a newly created blank tile. Save this file under boot.py in WorkSpace and upload it to the ESP chip. The program starts automatically the next time the reset or switching on.

Test programs

Programs from the current editor window in the Thonny-IDE are started manually via the F5 button. This can be done faster than the mouse click on the start button, or via the menu run. Only the modules used in the program must be in the flash of the ESP32.

In between, Arduino id again?

Should you later use the controller together with the Arduino IDE, just flash the program in the usual way. However, the ESP32/ESP8266 then forgot that it has ever spoken Micropython. Conversely, any espressif chip that contains a compiled program from the Arduino IDE or AT-Firmware or Lua or ... can be easily provided with the micropython firmware. The process is always like here described.

Preparation of the AZ onboard

The board is delivered with a sketch that checks the function of the sensors and the measured values ​​in a terminal program such as Putty outputs. However, this only works if all three break out boards are infected.

Figure 3: Edition with the demosoftware

Figure 3: Edition with the demosoftware

Even with our development tool Thonny, this works when we First connect the AZ-EONboard to the bus and then start Thonny.

But we want to write and run our own program in Micropython. The first step to the goal is that we burn a corresponding Micropython core on the ESP8266 that overwrites the demo program. So first load them Firmware down and then follow of these instructions. The ESP8266 then reports in Replica, Thonny's terminal, about Sun:





Then it is already time for the first attempts at walking. Inputs in Replica Become in this script fat formatted, the answers from the ESP8266 italic. We want to see if the ESP8266 can contact the sensorboard. To do this we have to do the classes Pin and Softi2c import. Then we instance a bus object and use it for a round recall who is there.





In the listthe function scan() returns, the hardware or device address of the BH1750 chip, 35 decimal or 0x23 hexadecimal can be found. So the connection works.

Now we connect our OLED display with four jumper cables on a different socket strip. The cables are necessary because the pins on the display have a different order than on the AZ-EONboard. The assignment is the following:

Display: AZ-Eoneboard

VCC: +

GND: -

SCL: SCL

sda: sda

Figure 4: OLED connected

Figure 4: OLED connected





We see that a second device with the address 60 = 0x3c has registered: the display. We also test that. But so that the next commands also work, we must first have the files oled.py and SSD1306.PY Upload to the flash of the ESP8266. We import the OLED class and create a display object.





The text appears in the middle of the first display line because we wrote from column 2 and the text consists of 14 characters. A line holds a maximum of 16 characters.

Next we start the driver module for the BH1750.

The class BH1750

We have to do two things to access the inside of the BH1750. A story is the conversation with the chip via the I2C bus. The other, more extensive thing, is the control of processes on the chip, either by accessing the internal register (storage points), or, as here, the sending of commands and picking up the data. Both steps are usually dissolved differently from chip to chip. As always, we start with the import business.





The declaration of the BH1750 class follows the determination of a few constants, in advance the device address and then the codes for different commands. We can from the Data sheet of the BH1750 remove.

Figure 5: Command overview

Figure 5: Command overview

The method init() places the constructor BH1750() of the class BH1750 dar. As arguments, when calling in the position parameter I2C The I2C object, and optionally in the keyword parameters ADR, mode and fak Transfer further data to the routine. If the parameters are not listed on the call, then take on the default values.





So that the values ​​are also available in other methods of the class, we assign them to instance attributes. All objects belonging to an instance are made by a preceding self defined and referenced. So the instance attributes are I2C, hwad, latency and factor. With poweron() and fashion() If defined methods are called up below, referenced. The print command tells us that the object has been created and tells us the hexadecimal representation of the hardware address of the BH1750.

The BH1750 is particularly easy to pick up measured values ​​because the chip always sends data, the combination of two bytes. So we only need to define one method that reads two bytes from the I2C bus. The MSB, the higher -quality byte, comes first.





The ESP8266 receives the two bytes and packs them for further processing into an object that follows the buffer protocol. That can be a bytes-be object, or like here, that Bytearar Buf. The function I2C.Readfrom_into() First sends the hardware address and then shovels the received bytes into the buffer. The plot in Figure 6, which I recorded with my Logic Analyzer and the Logic2 program from Saleae, shows what this looks like when transmission on the lines.

Figure 6: Read data from the BH1750

Figure 6: Read data from the BH1750

The transmission begins with a start condition, SCL = 1, sda goes to 0. The hardware address is always given with 7 bits, the eighth bit is attached to the right to the address, the Write-Read bit, here it is a 1 . This tells the BH1750 that he should send data. When sending a command to the chip, this bit 0. From 0x23 is 0x46.

With every rising clock flank, the controller samps the SDA line, which means that he looks at the level on the line. After eight clock flanks, the BH1750 pulls the SDA line to 0. With this Acknowledge-bit (ACK-BIT), he indicates that he recognized the address as his. The ESP8266 now knows that it has to prepare for the receipt of the data. With every falling clock flank, the BH1750 now places a database on the SDA line that the controller samps with the rising flank. If the reception has worked without errors, the ESP8266 now sends the ACK bit. The BH1750 then puts the second byte on the way that the ESP8266 acknowledged with a nack bit, not Acknowledge. The controller ends the transmission with a stop condition.

With the method command() we send a command to the BH1750, which we in CMD hand over as an integer. We just stored the values ​​as constants.





Now Micropython cannot send this value, which is actually a 32-bitz number as an integer value. Firstly, the BH1750 would not know about the four bytes and secondly, Micropython refuses to send objects such as integers of floating point, lists and other higher objects via the bus. For this purpose, the Softi2c class would have to provide routines for the automatic type conversion in buffer protocol-compliant objects. So let's stuff the command byte into the cell of a bytearar, so that Micropython can do something.





What is said here applies in the same way for the SPI bus, the serial uart interface and the WLAN interface.

What we have just sent to the BH1750 is the power-on command. The method poweron() does the same by that PwronCommand to the method command() is handed over. Works analogously powerdown().









Figure 7 shows an overview of the conditions of the BH1750 and the transitions from one to the other.

Figure 7: The states of the BH1750

Figure 7: The states of the BH1750

The BH1750 knows various measurement methods. Basically there is a single shot mode and a permanent run mode. Each mode has three different levels of the Lowres resolution, Highthres and Highres2, accordingly 4 lux, 1 lux and 0.5 lux. With the method fashion() we can set the corresponding mode. In order not to do anything wrong, we first check whether the value handed over is included in the list of permissible commands. If this is not the case, an assermentation terror is reported.





Because we cannot query the current mode of the BH1750, we remember the value in the instance attribute mode and then send the command. If the parameter is left out when the call, the method provides the value of the instance attribute mode back.





Before the reset command can be sent, the BH1750 must be in the power on state. The note is on page 5 of the Data sheets. By commanding, only the registers with the last measured value are set to 0.





With start() we add a single measurement. We can do the desired mode in the parameter fashion hand over. The default value is presented None. If the call is not an argument for mode handed over, then the value of the instance attribute mode used to start the measurement. The measurement duration will list Wait taken. We get the index to the list value from the two lowest quality bits in the commandobytes, i.e. 0, 1 or 3. The index 2 cannot occur. In order for the assignment of the list elements to the modes, we need a third element that I simply set to 0.





The setting of a single shot mode can only be made if Bit 5 is set in the command-byte. The IF query ensures this. If it is not set, we will throw a valueeror exception. The main program must intercept this, otherwise the program will be canceled.

If everything has fit, the mode is set and the individual measurement is triggered. The list provides the minimum waiting time until the result is provided Wait, 180 ms for Highres modes and 24 ms for lowres mode.

Now you can adjust the measurement time within certain limits. This becomes necessary if the sensor is covered with a protective glass. Despite the transparency, each glass absorbs part of the light energy, which must be compensated for by an extension of the measuring time. This extension factor must of course be taken into account when calculating the waiting time. For safety's sake, we always take the larger of the two values. Sleep_ms() Then send the ESP8266 briefly into the dreamland.

Regardless of whether it is a single shot, or automatic measurement, the Lux values ​​are used by the method Luminance picked up and prepared.





The bytearar, that reap() delivers, we unzip into the local variables right away Hb and LB. When the mode Highres2 was active, an additional divider 2 is necessary, says the data sheet on page 11 below. We solve this through a conditional expression. The formulas for calculating the illuminance on page 11 are mathematically wrong, brackets are missing.

Illuminance by 1 Count (LX / COUNT) = 1 / 1.2 *(69 / x) must be called:

Illuminance by 1 Count (LX / COUNT) = 1 / (1.2 *(69 / x)), because with a longer exposure time, a higher value for the luminance must also come out.

We push the MSB to the left by eight positions and ornament With the LSB. This creates a 16-bit data word from two data bytes. This is due to the product from 1.2 and the return value of the correction factor and through divider to divide. The illumination strength comes out in Lux.

In order to change the measurement time, we have already discussed this briefly above, there are two commands. The higher -quality bits tell the BH1750 what to do with the rest.

Figure 8: This changes the measurement duration

Figure 8: This changes the measurement duration

The routine period() takes a value from the interval [31… 254] and places it in the instance attribute _latency from that we in the method luminance() need. Then the correction factor of the measurement time is calculated. The following two lines prepare the handed over so that the two commandobytes arise from it. In the data sheet you ask yourself at this point (Figure 8) how that is meant. On page 11 it becomes clearer. The background to the procedure is probably that each command should only consist of one byte. In addition to the payload, the correction value, a key must also be transmitted that tells the BH1750 what to do with the payload. Ultimately, a payload byte then turns into two command-bytes.





So we push the upper three bits of the date, which we through Fierce with 0xe0 = 0b11100000, around five positions to the right and ornament them on the key part Changemth = 0B01000000. We win the lower five bits out with 0x1f = 0b00011111 and or or on Changemtl = 01100000. Then the commands are transferred to the BH1750. Becomes period() called without an argument, the method returns the current value of the correction bytot.

Would you like a little mysticism at the end of the program? - We made a measurement without sensor cover and received the value 587 lux as the result. With a glass cover we measure 391 lux. In order to get back to 587 lux, we have to extend the measurement time with a factor of 1.5 = 587/391. What kind of correction byte does it include? It would be nice if there was a method for conversion. Here you come together with a little micropython mysticism.





The method is used to query the correction factor factor(). @property Is a so -called Decorator. It makes the query in the form possible, as is common with variables, you only indicate the name, the brackets fall away. So be the instance attribute _factor from the value 1.5 then delivers factor just this value. Without the decorator you would have to write factor(). @Property therefore makes the return value of a function as referenced as a simple variable.

Why do we do that? We could just be the instance attribute _factor Query directly, for example.





Two reasons speak against it. First, in object -oriented programming, it is part of the fine way not to refer to variables directly. You don't ask directly and you do not assign values ​​directly. Micropython has not installed this access protection, but we can force it. It is not necessary that the user of a program knows the identifiers of attributes and variables. He should only work with the values ​​behind it.

Second, a user/programmer should not be able to assign any values ​​that may be able to crash the program. In fashion() and period() we have with the assert-instruction ensures security. By compiling our module, we can turn the script into a non -readable file that is as executable as the script. Which methods and attributes hide behind it is then no longer visible. We only reveal what we want to release to the user/programmer. By working with the Decorator @Property, we can hide the true name of the variables to be called up. Even more, it could be that further steps have to be taken to call up, which, for example, should change the appearance.

The situation is similar if we know the factor and want to calculate the correction byte from it. We also use a decorator for this, @factor.setter. He also hides the method underneath so that it can be treated like a variable. Of course we could attribute _factor occupy directly. But who then ensures that the value is in the permissible area?

In vala Let us hand over the desired correction factor, which is immediately checked for valid values. The instance attribute _factor If we are updated, then we call the method period() with the calculated correction byte that does the rest. The value of _latency Let's be returned. If the method would not have a decorator, we would have to write Factor (1.5), so we write like a variable Factor = 1.5 And still let the check go through and calculate another value.

What I am here factor have also shown, by the way, could also be included fashion, luminance and period make. Feel free to try it out!

Demo and test

A simple one Demo program shows the use of the module bh1750.py.





The I2C object I2C is used twice, we hand it over to the constructors of the BH1750 and OLED class. In the endless loop, we delete the display, have the heading out, followed by the current correction factor and the luminance value. The argument False leads to the fact that the data is only written in the display buffer. In the last line, this argument is missing, which causes the entire data buffer to be transferred to the display. This saves computing time and suppresses the display.

A Second programs helps to determine the correct correction factor by trial and error.





After displaying the values, a value for the factor is required in Repl. After entering, we convert the string into a flow of flow and call the setter factor On - short break - next round. With a luxmeter next to our sensor, we now capture the brightness value and change the factor until both devices indicate roughly the same value. With the "S" button we can save the value and with "E" the loop is left.

A little solder at the end

Now we can record gorgeous measured values, but we cannot connect an actuator. One way out would be the use of a PCF8574 or MCP23017 type, both of which are controlled via the I2C bus.

I chose a different way to bust up the AZ-Eoneboard. I briefly heated up the soldering iron and on the board the unused and also not removed GPIO connections provided with short wire pieces and slices. The GPIOS 0, 2, 15 and 13, 12 and 14 are available to me. If necessary, you could also expand the I2C bus by also using wires to pins 4 and 5.

Figure 9: port expansion

Figure 9: port expansion

Figure 10: Pin occupancy ESP8266 12F

Figure 10: Pin occupancy ESP8266 12F

Figure 11: AZ-Eoneboard in the extended test

Figure 11: AZ-Eoneboard in the extended test

In the next episode, we will deal with the SHT30 on the AZ-EONboard and write a module for it. See you then!

DisplaysEsp-8266Projekte für anfängerSensoren

2 comments

Jürgen

Jürgen

I had seldom problems with boot.py, but You are right, using main.py is the better solution. Thanks for Your contribution.
Jürgen

Frank Carius

Frank Carius

Please edit the section about “Autostart”. You should never use the boot.py, because it may block any future usage. I prefer main.py with a delay (time.Sleep(5)) at the beginning to allow a break. See
https://www.msxfaq.de/sonst/bastelbude/esp8266/micropython.htm#boot_py_und_main_py

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery