# Build an online battery monitor :battery: ###### tags: `Tag(st222eu)` > **Author**: Sotirios-Ilias Tsivras (so.tsivras@gmail.com) > **Project outline**: In this tutorial the author will describe a way to monitor the battery voltage of an off-grid **photovoltaic (PV)** system :sunny: ### Table of Contents [ToC] ## :pencil2: Objectives - [x] Record the battery voltage and the current flow of a PV system - [x] Send an email notification to the user in case the battery voltage is very low The main objective of this tutorial is to develop a method for recording the energy flow inside a small-scale PV system by developing an **Internet of Things (IoT)** application. As an introduction we will just measure the current flowing to and from the battery, as well as the battery voltage. This application can be easily extended to measure other parameters, such as the ambient temperature, the temperature at the back of the PV module etc. The code developed for this application is written in **Python** programming language. In the next tutorials the author will also develop some **machine learning** (ML) methods for analyzing the data generated from this IoT application. ## :clipboard: Components - [x] 30W poly-crystalline PV module - [x] 10Ah @ 12V lead acid battery - [x] 12V / 10A PWM solar charge controller - [x] Pycom's LoPy4 device - [x] Pycom's expansion board - antenna - transparent case - [x] INA260 current sensor - [x] Lilypad temperature sensor (optional) - [x] Breadboard and jumper-wires ## :pencil: A few words about IoT IoT is a set of objects (things) or sensors that exchange information in order to automate a specific task. In this example, the objective is to automate the task of keeping an eye whether the battery of an off-grid PV system has been discharged. This is a crucial task as **the number of charge-discharge cycles** of the battery is decreased when the depth of discharge is high. ### LoPy4 Pycom's LoPy4 is a MicroPython enabled development board, perfect for IoT solutions as it is low-power and very flexible. It is suitable for LoRa and Sigfox networks which become rather common around the globe. ### MicroPython ![](https://i.imgur.com/jI0whk6.png) MicroPython is an optimized implementation of Python programming language that uses a subset of the Python standard library in order to run on microcontrollers. ### LoRa ![](https://i.imgur.com/edw3pq8.png) LoRa (**Lo**ng **Ra**nge) is a low-power wide-area network modulation technique. It uses the license-free sub-gigahertz radio frequency band, like EU863-870 (863-870 MHz) in Europe. **LoRaWAN** is the networking protocol built on top of the LoRa modulation technique. ### PyBytes ![](https://i.imgur.com/oT1OROu.png) This is an online device management platform for your LoPy4. Once you buy a LoPy4 you can create an account for free and register your device in order to start recording events. ### TTN ![](https://i.imgur.com/Qs4tiy2.png) **The Things Network** (TTN) is an ecosystem that creates networks of objects and sensors that use LoRaWAN. The network is expanding and once a gateway is nearby (at a distance of ~7 km or less) you can connect your IoT device without needing a Wifi connection. For more information you may visit the official TTN's website: https://www.thethingsnetwork.org/ ### Ubidots ![](https://i.imgur.com/uqlABL9.png) Ubidots is a platform that gives the ability to generate graphs and events using data collected from IoT applications. TTN gives the ability to communicate with Ubidots and send real-time data in order to be processed. ### INA260 The INA260 current sensor can measure the DC current flowing over a circuit with high precision. It can also measure the bus voltage and as a result, the power consumption on the load side. For more information you may visit Adafruit's official website: https://www.adafruit.com/product/4226 ### Lilypad Lilypad is a small and low-cost thermistor type temperature sensor. Due to it's small size it can even be attached at the back of a PV module in order to record it's surface temperature. For more information you may visit Sparkfun's official website: https://www.sparkfun.com/products/8777 # Implementation steps ## :computer: Step 1: Computer Setup - [x] Install Atom & Pymakr - [x] Install Visual Studio & Node.js In order to develop the code and upload it to the LoPy4 device, I installed the Atom software and the PyMakr plugin for running Python code which is quite simple to follow: https://flight-manual.atom.io/getting-started/sections/installing-atom/ For running Atom you need to install the Desktop Development package with C++ of Visual Studio: https://docs.microsoft.com/en-us/visualstudio/install/install-visual-studio?view=vs-2019#step-3---install-the-visual-studio-installer Node.js, which is a package for running JavaScript, will probably be needed : https://nodejs.org/en/. ## :satellite: Step 2: Connect LoPy4 - [x] Update firmware - [x] Run code example In order to connect to PyBytes you will probably have to update your firmware. Pycom offers an easy tutorial for this purpose: https://docs.pycom.io/updatefirmware/device/ Once you have succesfully connected your LoPy4 with a USB cable, you should create a new **project** (in the following figure the project is called "Sensors") including a **lib** folder (for saving the library of the INA260 sensor) and a **main.py** file (that will automatically run from your device). In the following figure there is an example of running a test code: ```python=1 import math print('2^2 = ',(math.pow(2,2))) ``` ![](https://i.imgur.com/MFdpdlq.gif) ## :package: Step 3: Sensor Setup For this application we are going to use a small poly-crystalline PV module with a rated power of 30W. This module generates this power with a nominal voltage of 20 V and a current of 1.5A. The electricity generated from this PV module will be fed to a small lead-acid battery via a solar charger that prevents the battery from over-charging :shield:. The charge controller will also be connected to 2 LEDs with a power consumption of 5 W each that will be automatically switched-on from dusk till dawn. Using the USB ports we will also power the LoPy4 device to send inforation over LoRa. For connecting the sensors with the expansion board, we can make use of a simple breadboard and jumper-wires. The Lilypad temperature sensor generates output from 0 up to 3.3 V (analog). Thus we make the following connections: - Lilypad + :arrow_right: LoPy4 3.3 V - Lilypad - :arrow_right: LoPy4 Gnd - Lilypad S :arrow_right: LoPy4 Pin16 For the INA260 current sensor we make the following connections to the LoPy4 ports: - INA Vcc :arrow_right: LoPy4 3.3 V - INA Gnd :arrow_right: LoPy4 Gnd - INA Scl :arrow_right: LoPy4 Pin8 - INA Sda :arrow_right: LoPy4 Pin7 The rest connections are shown in the following figure: ![](https://i.imgur.com/gsZbMkX.png) :::info :bulb: **Hint:** You should connect all Gnd's with the negative pole of the battery in order to make correct readings. ::: Download the following library form the INA260 sensor and save it inside the **lib** folder of Atom: https://github.com/iot-lnu/applied-iot/tree/master/sensor-examples/INA260%20-%20Digital%20Current%20and%20Power%20Monitor Then run the following examples in order to check if everything is connected correctly: ```python=1 # test Lilypad import machine adc = machine.ADC() apin16 = adc.channel(pin='P16') # EXAMPLE: Create a Lilypad object, collect data in the loop and print it i=0 while i<10: # pin 16 millivolts = apin16.voltage() celsius = (millivolts - 500.0) / 10.0 temperature16 = int(celsius) print('sent temperature:', temperature16) time.sleep(5) i+=1 ``` ```python=1 # test INA260 from machine import I2C from lib.ina260 import INA260 import time sda = 'P7' scl = 'P8' bus = I2C(0, mode=I2C.MASTER, baudrate=100000, pins=(sda, scl)) stuff = bus.scan() time.sleep_ms(50) c = INA260(bus) i=0 while i<10: c_v=0 c_c=0 c_w=0 for ii in range(5): c_v+=c.voltage() c_c+=c.current() c_w+=c.power() time.sleep(1) print("Bus voltage:", c_v/5, "V") print("Bus current:", c_c/5, "A") print("Bus power:", c_w/5, "W") i+=1 time.sleep(5) ``` ![](https://i.imgur.com/uiCYhwN.gif) ## Step 4: Create accounts You need to create accounts to the following websites: - **Pybytes**: This is the device management platform for your LoPy4. After creating a new account you should configure your wifi network (if available) in the "Congifgure Networks" tab. For more information you may visit the following link: https://docs.pycom.io/pybytes/gettingstarted/ - **TTN**: For checking the coverage in your area you should visit the following website: https://www.thethingsnetwork.org/map. At first you should create an account: https://account.thethingsnetwork.org/register. Then you should create an application and register your LoPy4 device. Then you should be able to send messages to TTN using the code given in main.py which will be analyzed in the following paragraphs. - **Ubidots**: You should create an account here: https://ubidots.com/stem/. Then create a data-plugin and choose "The Things Stack". Then you should be able to create a webhook to TTN and a decoder for analyzing the data sent over the network. ## Step 5: Upload files Finally you should create a main.py file to your project in Atom and write the following code: ```python=1 # main.py - it runs automatically from lopy4 from network import LoRa import time import binascii import socket import machine import struct from machine import I2C from lib.ina260 import INA260 # connect to network using 868MHz frequency lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868) # authenticate the application and connect app_eui = binascii.unhexlify('xxxxx') app_key = binascii.unhexlify('xxxxx') lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0) i=0 while True: # wait until the module has joined the network if not lora.has_joined(): time.sleep(10) i+=1 else: # create a socket object s = socket.socket(socket.AF_LORA, socket.SOCK_RAW) s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5) s.setblocking(False) # read temperature adc = machine.ADC() apin = adc.channel(pin='P16') # read INA260 sda = 'P7' scl = 'P8' bus = I2C(0, mode=I2C.MASTER, baudrate=100000, pins=(sda, scl)) stuff = bus.scan() time.sleep_ms(50) c = INA260(bus) # collect 10 measurements and take the average i=0 while True: c_c=0 c_v=0 t_c=0 for ii in range(10): c_c+=c.current()*1000 c_v+=c.voltage()# mA millivolts = apin.voltage() celsius = (millivolts - 500.0) / 10.0 t_c+=celsius time.sleep(1) current_i = round(c_c/10,1) voltage_i = round(c_v/10,1) temperature_i = round(t_c/10,1) # send to TTN/Ubidots payload = struct.pack('>hhh', int(current_i*10), int(temperature_i*10)) s.send(payload) # print results print('sent temperature (C):', temperature_i) print('sent current (mA):', current_i) print('sent voltage (V):', voltage_i) # wait 100 seconds before sending again time.sleep(100) ``` Then press the **upload** button to Atom to copy the code to your machine. # Results If everything is correctly done to your project, you should be able to create dashboadrs and events to Ubidots. In the following figure I've created a graph using Ubidots, including the battery voltage and the current flowing trhough the circuit. ![](https://i.imgur.com/ggBagxn.png) As you can see during night, the overall current consumed by the charge controller, the LoPy4 and a lamp is 14.6 mA. Moreover, the battery voltage drops to nearly 12.1 V at midnight. So it is reasonable to create an event and having a notification email when the voltage drops below 12 V. # Aknowledgements Many thanks to: - [x] **Linnaeus University** (especially TAs) for introducing me to the IoT world - [x] **Dalarna University** for introducing me to the solar energy world ![](https://i.imgur.com/YJ915Gq.png) ------------------------ YouTube Videos (this is from a previous version of the project - a new video will be uploaded soon) {%youtube Qqxhb5XGj8Y %}