# Part 2: Sensor Connection & Data Reading ###### tags: `TA Stuff ESP32` `PyCom` `Heltec` `ESP32` In this tutorial, you will read about the pinout in your development board, how to connect a sensor to your board, and finally, use the sensor(s) in your code. This tutorial is helpful for both Heltec and PyCom board owners. We will: + read about your development board pinout and the meaning of them. + read about how to connect a sensor physically to your board. + read data from basic **Analog** and **Digital** sensor. + read about how to get a library and use it in your code. + read about how to connect several sensors with the help of a breadboard. As always, we'll continuously update this walkthrough. **Is there anything missing or unclear, or have you experienced some issue? Please add a comment.** You do this by highlighting the text and then you can write a comment on the highlighted part. You need to log in/create an account on hackMD first. :::info (**⚠️ INTERACTIONS BETWEEN MICRO CONTROLLER AND SENSORS - The fundamentals To use sensors, internal or external, the micro controller must know how to use these. This is done by "drivers" that is called libraries. These libraries include instructions (code) that will bring a certain function to work with, analog to digital conversion or the ability to calculate mathematical equations etc., internally in the controller. Different types of libraries are required when working with external sensors or "tools" for the controller, temperature sensor or a motor etc. These libraries are built up by a data structure called "class", and is a complex data structure. A simple data structure is for example "integer", which can contain numbers like: -1, 0, 1 and so on, or "float", which can contain floating numbers like: 2.92413 etc. The "class" can describe more complex sensors or tools, and contains two nessesary properties: (1)information about the sensors construction, and (2)information about the sensors function. These two properties are nessesary to create a "relationship" between the micro controller and the sensor. Libraries, on the other hand, contains classes.**) ::: <br> ## Development Board Pinout You can see and download the PDF version of pinout for both **PyCom** and **Heltec** board below: ### PyCom FiPy ![](https://docs.pycom.io/gitbook/assets/fipy-pinout.png) This schematic shows information about pins on your FiPy and their usage (pdf available [**here**](https://docs.pycom.io/gitbook/assets/fipy-pinout.pdf)). You will regularly come back to this and eventually familiarize yourself with it. (For **LoPy4** pinout see [**this**](https://docs.pycom.io/datasheets/development/lopy4/)). <br> ### Heltec (WiFi LoRa 32 V2) ![](https://i.imgur.com/e1k5mgq.png) This schematic shows information about pins on your Heltec and their usage (pdf available [**here**](https://github.com/H-Ryan/Heltec/raw/main/PyCom%20MicroPython/heltec_pinout.pdf)). You will regularly come back to this and eventually familiarize yourself with it. :::info (**⚠️ When referring to a pin in this tutorial, we mean the turquoise-colored boxes in FiPy pinout and gray-colored boxes for Heltec boards. To tell them apart you will find the letter **P** before the number, like; `P10`, `P23` etc.**) ::: <br> ### ESP32 Generic Board ![](https://i.imgur.com/gxpTQ3f.png) <br> This schema belongs to the Generic ESP32 Board and you can see the pinout, there exists different Generic ESP32 and each may have a different pinout. Please read the datasheet from the seller or google to find it for your board. :::info We flashed **PyCom** and **Heltec** in Part 1 tutorials with the PyCom version of MicroPython but if you have a generic board you can flash them with standard MicroPython which is slightly different from PyCom one. If you flash your board with standard MicroPython you can read more about the functionalities [**here**](https://docs.micropython.org/en/latest/esp32/quickref.html). For example, one difference between PyCom MicroPython and Standard MicroPython is defining pins in the code. You can read about it [**here**](https://docs.micropython.org/en/latest/library/machine.Pin.html). ::: ### Analog to Digital You might first look at the **Analog Pins** that are called `ADC_#` in the schematic. ADC stands for Analog to Digital Converter - and what it does is take an input signal from your sensor, and convert it to a digital representation - something the computer can work with. The difference between analog and digital is that **analog** signals *vary*, they go anywhere between 0 and some other voltage, for example, 3.3V (or 5V); while **digital** signals are either 0 or that voltage - which means they are binary, _low_ or _high_ voltage - or in computer language, `0` or `1` (_false_ or _true_). Your computer works in binary, that's why we need an analog to digital converter to work with the signals. We will show how to use them in this tutorial. ### General Purpose Pins As you might note all PINs that start with `P#` are General Purpose Input/Output (`GPIO`) Pins and they can be connected to the sensors and be used by the `Pin()` method in MicroPython code. Although, if you use communication protocols like; **LoRaWAN** you may not use those ports which are connected to the *LoRa* chip (more will come in the **Part 3** tutorials). ## How to connect a sensor physically :::danger **⚠️IMPORTANT⚠️** + Disconnect the power/USB cable from the Development/Expansion board before connecting sensors or changing a sensor pin. This allows us to check that everything is correct before powering the board. + Always check if the sensor works on 5V or 3.3V before connecting your sensor to the board. If you are unsure check the sensor datasheet or consult it with a TA. + We recommend using colored wires to make it easier to distinguish which wires are which. + We recommend using a breadboard if you have several sensors it makes the connection more visible. ::: The basic sensors are generally quite easy to connect to the development board. They usually have 3 pins, one connects to 5V or 3.3V, another connects to the ground (GND, 0V), and one to a measuring pin, like `P16`. For example, to connect a TMP36 analog temperature sensor you could do as follows: ![](https://i.imgur.com/jGCQ4FQ.jpeg) <br> ![](https://i.imgur.com/YVCDxdX.png) <br> PyCom Board | Heltec Board :-------------------------:|:-------------------------: ![](https://i.imgur.com/biTboDo.jpeg =300x) | ![](https://i.postimg.cc/jKqzyJpL/IMG20220614174455-2.jpg =300x) <br> Connect the positive voltage leg to `3V3`, the ground leg to `GND`, and the output leg to any pin with ADC capabilities (in this case, `P16`). :::danger :warning:Some sensors have a flat and a curved face. For example, the TMP36 sensor mentioned above. Make sure to connect them in the same way as the pictures since otherwise, they might burn out. ::: To connect your sensors to the development board, a **breadboard** is very useful. They usually contain 2 longer rails on each side, to easily connect to $V_{dd}$ (Positive voltage, operating voltage) and __GND__ (ground, 0V) to all your components. Each row of a breadboard is numbered and contains a rail, to easily allow you to connect pins and wires. Each row of a breadboard is numbered and contains a rail as shown in the figure below, to easily allow you to connect pins and wires. ![](https://images.ctfassets.net/2lpsze4g694w/4RTiBRQJPNOQPDaKUh2brQ/68aae61ac17acde06aac093502e0b9f9/Breadboard_Anno.jpeg?w=800 =400x) ### Sensor connection examples Here's an [**album of some connections that we've made for common sensors and output devices**](https://imgur.com/gallery/DT0jhg6). You can make your diagrams like the ones above using the program [**fritzing**](https://fritzing.org/). Alternatively, you can visit our [github page](https://github.com/iot-lnu/applied-iot) and see if your sensor is listed under `sensor-examples`. If your sensor isn't in the album, nor in our github repository, then it's recommended that you read the datasheet of the sensor to figure out how to connect it. This can often be found from the same page you bought it, Sellers often provide datasheets or tutorials. [**Like this one, check it out!**](https://www.electrokit.com/uploads/productfile/41015/User_guide.pdf) If there's no available, try searching the sensor name + datasheet or tutorial. **If your sensor needs 5V** (often 3.3V works even when it's not specified) you can use the `Vin` port (**For PyCom Boards**) if your device is connected via USB to your computer (`Vin` is just the voltage that goes into your device, USB is 5V). On Heltec and other ESP32 boards, you have both `3V` and `5V` Pins. :::danger :warning:**PYCOM Users** - Do not use `VIN` as input if your device is already powered by a battery or through USB. If your device is powered on by USB or battery, then `VIN` should only be used as output, e.g. to power sensors etc.. ::: ## Basic Analog sensors Analog sensors are devices that produce the analog output. These sensors observe the change in external factors such as light intensity, speed of the wind, solar radiation, and others. The output of an analog sensor generally ranges between 0V to 5V (or 3.3V). In this section, we want to show you a typical example of how to do this in MicroPython. For this example, we'll use the [TMP36](https://www.electrokit.com/produkt/tmp36-to-92-temperaturgivare/), an analog temperature sensor. (It's similar to temperature sensor MCP9700 which followed in the Electrokit bundle) ![](https://i.imgur.com/8ldqjSn.png =200x) The first thing we want to do is to create an [ADC](https://docs.pycom.io/firmwareapi/pycom/machine/adc/#app) object for analog to digital conversion. This is the "thing" in our code we'll use to read from our sensor. ```python import machine adc = machine.ADC() ``` Next off, we want to define where we want our `ADC` to collect its input from, that is, which pin our temperature sensor is connected to on the Expansion board (PyCom), Heltec, or ESP32 board. ```python apin = adc.channel(pin='P16') ``` In this case, we've connected it to pin `P16`. Different pins do different things. If you feel adventurous, you can read up on what all pins do in [**FiPy**](https://docs.pycom.io/gitbook/assets/fipy-pinout.pdf), [**LoPy4**](https://docs.pycom.io/gitbook/assets/lopy4-pinout.pdf), [**Heltec**](https://github.com/H-Ryan/Heltec/raw/main/PyCom%20MicroPython/heltec_pinout.pdf), and for **ESP32 Generic** refer to your seller datasheet or google. We can now read our sensor. ```python millivolts = apin.voltage() ``` This reading comes as millivolts. To gather some useful data out of this, we have to convert it. This is common in the world of analog sensors, and to know how to convert the output of the sensor into something useful, we have to read its [datasheet](https://www.electrokit.com/uploads/productfile/41012/41012431.pdf) (or use Google). In the datasheet we find our conversion: $$ celsius = {(millivolts - 500)\over10} $$ Now we can make this into actually runnable code on our development board! Check this out! ```python= import machine import time adc = machine.ADC() apin = adc.channel(pin='P16') while True: millivolts = apin.voltage() celsius = (millivolts - 500.0) / 10.0 print(celsius) time.sleep(1) ``` This is just an example of an analog temperature sensor. However, reading from another kind of simple analog sensor would only differentiate in the last step where we convert from millivolts. ## Basic digital sensors Contrary to analog sensors, digital sensors only output high or low - also known as the binary values `1` or `0`; in layman's terms, the sensor is either "on" or "off" (more advanced digital sensors, such as the DHT11/22, outputs a series of 1's and 0's which your development board interprets - often requiring a [library](#Sensors-that-require-a-library). They could be anything from a basic tilt switch to a movement sensor. A prime example of a digital sensor is a [knock sensor](https://www.electrokit.com/en/product/knock-sensor/) (See figure below). ![](https://i.imgur.com/DRxvFgC.jpg =300x) The knock sensor detects, as you can imagine, knocks and vibrations. The middle pin needs to be connected to **5V** (3.3V might also work) and the pin denoted with a "**$-$**" should be connected to **Ground** (**GND**). If the sensor detects any vibrations, the pin denoted with an "**S**" is set to `0`. If *no* vibrations are detected, it is set to `1`. It is therefore pretty straightforward to extract the information from the sensor. ```python= from machine import Pin import time pin_input = Pin('P16', mode = Pin.IN) # This pin is the "S" pin as mentioned above while True: value = pin_input.value() # Get the value, either 0 or 1 if value == 1: print('No vibration detected') else: print('Vibration detected') time.sleep(0.1) ``` The code above continuously checks if the sensor has been disturbed. If it has been disturbed, the string `Vibration detected` is printed. Let's dissect the code into smaller pieces to understand what is happening: ```python from machine import Pin import time ``` Firstly we need to import the necessary MicroPython modules. The [`Pin` module](https://docs.pycom.io/firmwareapi/pycom/machine/pin/) lets us access your board data pins. ```python pin_input = Pin('P16', mode = Pin.IN) ``` The code above has created a `Pin` object. The chosen pin (`P16`) needs to be set as an input from the sensor. Therefore, set the mode of the pin to `Pin.IN`. ```python while True: value = pin_input.value() # Get the value, either 0 or 1 ``` By entering an infinite loop, we can check continuously for updates from the sensor. We extract the value by typing `value = pin_input.value()`, where `pin_input` is the variable name for our pin and `value()` is the function that return the value of the pin (`1` or `0`). ```python if value == 1: print('No vibration detected') else: print('Vibration detected') ``` We then check the value from the sensor to determine what message to print. ```python time.sleep(0.1) ``` Lastly, we let $0.1$ seconds pass before a new read from the sensor. ## Sensors that require a library These are often more advanced sensors, but can also be basic and the libraries just make life easier. In this section, we demonstrate how to use sensors that require a library. ### How to download libraries In our GitHub, there exist some libraries for some sensors which you can use. To download them you go to this [**repository**](https://github.com/iot-lnu/applied-iot) and follow the arrows in the below picture, libraries are in the `sensor-examples` folder with a sample code on how to use them. If your sensor does not have a library in our repo, you can try looking for one online or ask one of the teaching assistants for help. ![](https://i.imgur.com/PIsZFd5.jpg) **Note:** After downloading the zip folder you need to extract the downloaded files. ### How to import library To use the downloaded library, you simply copy the content of lib in the extracted folder and paste it under your lib folder, as demonstrated in the previous tutorial [here](https://hackmd.io/@lnu-iot/r1VgdjLdq). Once done, your project should look similar to the one shown below. ![](https://i.imgur.com/biFOCtE.png) **In each sensor folder of the repository, you will find a library (the lib folder) and example code that run or use it, if they require a library to run.** ### Use the library You can create your main file that uses the lib. All you need to do is to import the library in `main.py`. You may import the library from lib in 3 different ways: ```python= import library #imports the whole library file, #everything is accessible through dot-notation from library import className #only import a specific part from the #library import library as newName #imports the whole library file, however, #the library is renamed in this file ``` For example, the code below uses the LiDAR library. Read the comments in the code to learn how it uses the library. The datasheet can be found [here](http://myosuploads3.banggood.com/products/20200515/20200515021121SJ-PM-TF-LunaA03ProductManual.pdf). ```python= # Import necessary modules and our own LiDAR library from machine import I2C import utime import sys from lib.lidar import LIDAR # Our LiDAR library # From the TF-luna datasheet, we learn that # the sensor has the adress 0x10 LIDAR_ADDRESS = 0x10 # We create an I2C bus, to which we connect our LiDAR # P7 = SDA of the sensor # P8 = SCL of the sensor i2c_0 = I2C(0, mode=I2C.MASTER, baudrate=400000, pins=('P7', 'P8')) utime.sleep_ms(50) # We scan the bus for sensors # Note that multiple I2C sensors can be found # if they're connected to this bus (bus 0, P7 & P8) slaves = i2c_0.scan() if LIDAR_ADDRESS not in slaves: print('Bus error: Please check LIDAR wiring') sys.exit() # We create a sesnor object, defined in our library lidar = LIDAR(i2c_0, LIDAR_ADDRESS) lidar.set_min_max(20, 150) lidar.set_frequency(250) # We print the distance every 10 milliseconds in an infinte loop while True: print(lidar.distance()) utime.sleep_ms(10) ``` Your code will look something like this in Atom ![](https://i.imgur.com/iCcGyUn.png) <br> ### Use Library for onboard OLED (Heltec Boards) Those who own a **Heltec WiFi 32 LoRa** have an onboard OLED and in this part, we try to make a new project download a library, and try the OLED to show some text on it. Follow these steps: * **Step 1:** Create a folder on your computer ( `First Project` ). * **Step 2:** Open Atom and click on `Add Folder` from the left panel then open created folder. * **Step 3:** `Add File` by right click on your opened folder and naming it `ssd1306.py`. * **Step 4:** Open [**this page**](https://github.com/Hiverize/FiPy/blob/master/sensors/ssd1306.py) and copy the content of the library file of OLED to your newly created file and save it. * **Step 5:** Create another file named `main.py` and copy the following code into it, then change `Your_WiFi_Name` and `WiFi_Password` to your home router credentials and save: ```python= import ssd1306 import time from machine import Pin from machine import I2C # Start OLED oled_width = 128 oled_height = 64 # Setup the I2C pins i2c_scl = Pin('P4', mode=Pin.OUT, pull=Pin.PULL_UP) i2c_sda = Pin('P3', mode=Pin.OUT, pull=Pin.PULL_UP) i2c = I2C(0, I2C.MASTER, baudrate=100000, pins=(i2c_sda,i2c_scl)) time.sleep_ms(500) oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) oled.fill(0) oled.text('Heltec OLED', 0, 0) oled.text('HELLO WORLD', 0, 25) oled.text('LNU', 0, 55) oled.show() ``` <br> * **Step 6:** Now upload the files to your board from the upload project button: ![](https://i.imgur.com/IIkTp5D.png) <br> * **Step 7:** Your board will reset then tries to connect to your home WiFi and print three lines on your OLED. ![](https://i.imgur.com/cL2IKiP.jpg) <br><br> ## Connect multiple sensors Connecting multiple sensors works just like connecting one sensor. You could use the **+** rail on the breadboard where you connected your voltage output from your device and the **-** for GND. The rail goes along the whole breadboard so you can connect several sensors from these rails. ![Step 1](https://i.imgur.com/a2y7wDb.jpg) ![Step 2](https://i.imgur.com/2n6B5Xl.jpg) In the example, we are connecting 3 different kinds of sensors/actuators. The first one from the right is the simplest. It's a hall effect sensor (analog). Next is the DHT sensor which measures temperature and humidity. It requires a library to communicate with it. Last but not least we have an OLED display (SSD1306) the same as the one on the Heltec but here you can see it as a separate part for the other boards as previously seen it uses the I2C protocol. Although it's not a sensor it connects like any other I2C sensor using the SCL and SDA pins. We can now start connecting sensors. We start by connecting the analog hall effect sensor. We can pick any pin that has An analog to digital converter but make sure to use `ADC1` instead of `ADC2` (marked in the pinout) since for example `ADC2` is used for wifi on the **FiPy**. ![Step 3](https://i.imgur.com/J9HzIcB.jpg) Now we can move on to connect the signal pin of the DHT sensor. We can use any input digital pin but make sure to pick one that doesn't have any other usages that might conflict with the sensor. We pick pin P20 since it is right after the previous one for a tidier diagram. ![Step 4](https://i.imgur.com/uAN6mZd.jpg) Now we can connect the display. For I2C we have to use 2 specific pins. They are marked as SCL and SDA in the pinout diagram of the FiPy. We can actually use the same 2 pins for multiple I2C sensors without a problem, but that only applies to I2C (and SPI) sensors. The SDA pin on the FiPy is P9 and the SCL pin is P10 so we connect to those pins. ![Step 5](https://i.imgur.com/DOrKAHz.jpg) :::danger **⚠️Double and triple check The connections before connecting power.** ::: If all the connections are correctly in place then all that is left to do is to write/modify the code with the pins we have just connected. <br/> <style> .markdown-body code{ font-size: 1em !important; } .markdown-body .a{ font-size: 5em !important; } .markdown-body pre { background-color: #333; border: 1px solid #333 !important; color: #dfdfdf; font-weight: 600; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { background: #000; } .markdown-body table { display: table; padding: 1em; width: 100%; } .markdown-body table th, .markdown-body table td, .markdown-body table tr { border: none !important; } .markdown-body table tr { background-color: transparent !important; border-bottom: 1px solid rgba(0, 0, 0, 0.2) !important; } </style>