# 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 
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 
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 
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 
**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 
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)))
```

## :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:

:::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)
```

## 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.

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

------------------------
YouTube Videos (this is from a previous version of the project - a new video will be uploaded soon)
{%youtube Qqxhb5XGj8Y %}