LoRaWAN Battery Monitor Part 2

Matt Gilpin

Issue 62, September 2022

Build this Raspberry Pi-based remote wireless battery monitoring system to keep watch on your 12V battery system.

Last month in Part 1, we introduced you to LoRaWAN technologies and gave you a broad overview of our project. In this issue, we show you how to build and configure the project.

The Main Build

With all the theory and prototyping out of the way, it’s time for the construction. Although there is no right or wrong way to put the board together, I have a personal preference. Feel free to solder the components in whatever order you like.

The first thing on the list are the passives. We only have one capacitor on the board, and to be honest, it’s not absolutely critical, so it can be omitted if desired, but having it there should provide extra stability.

While I’ll only solder one “measuring channel” in, you can solder up to five – from Pin A0 to A4. That way, you can measure up to five voltages at once. Here is the schematic for each additional channel. Note that this is able to accept up to about 15.6V. If you need to go higher, you will need to adjust the resistor divider.

Parts Required:PakronicsCore Electronics
1 x MPM3610 5V Buck-ADA4739
1 x Adafruit RFM95 FeatherWing-ADA3231
1 x 915MHz Spring Antenna-ADA4269
1 x Adafruit RP2040 FeatherADA4884ADA4884
1 x Feather Proto WingADA2884ADA2884
1 x Feather Stackable HeadersADA2830ADA2830
1 x RV-3028 RTC Module-CE07922
1 x Screw Terminals-POLOLU-2440
1 x 10k resistorDF-FIT0119-
1 x 56k resistorElement14: 9342079-
1 x 15K resistorDF-FIT0119-
1 x 100nF capacitorElement14: 2395773-
1 x TN0104N3-G N-Channel (BS170 alternative 1017687)Element14: 2851614-
1 x VP3203N3-G P-ChannelElement14: 2810154-
1 x M205 Inline fuse holderElement14: 2292906-
1 x M205 500mA fast blow fuseElement14: 2461219-
1 x IP65 ABS enclosureElement14: 1094699-
1 x Cable GlandsADA761-

Parts Required:

After the passives are installed, if you wish to solder in the optional PMOS and NMOS parts for the extra low sleep current, now would be time to do so – the schematic is below. Otherwise, we can solder the required P-channel and N-channel MOSFETs for the power side of the circuitry to ensure that the board is only powered when it is required.

Next, we can solder some of the linking wires and the terminal block. We’ll wait until a later stage to solder in the remaining wires as it may make soldering the other parts a little more challenging.

With that soldered in, it’s about time that we added the two main components to this board: the RTC and the voltage regulator. But before we do that, we must prepare the RTC.

In order to prevent the power LED from being on constantly, the first step is to cut the "PWR LED" trace. After that, we can solder some right angle header pins into the RTC module and then some straight header pins into the buck module.

With these soldered, we can solder in the remaining wires and header pins.

As you can see, it's getting quite messy – it’s the price you pay for a compact form.

The RP2040 Feather board itself and the Radio FeatherWing are the last components we need to solder together for this project. Actually, these were constructed during the prototyping phase so I won’t go through them since soldering the RP2040 Feather is a rather simple process. However, I would like to show the connections needed for the Radio FeatherWing.

I do want to point out that we have a few choices for an antenna. So that you can use an external antenna, there are pads for a UFL or SMA connector. A simple wire antenna, like the one I have used, can also be inserted through a pinhole. I would advise attaching a SMA or UFL connector and utilising an external antenna to achieve the most range possible if you were deploying this from a considerable distance away from a gateway where range would be a problem. I chose to utilise the most basic antenna that can fit within a small enclosure as my use case is quite short range.

With all of our stages soldered up, we can finally stack the RP2040 Feather on top of the RFM95 FeatherWing and move on to the next stage.

Since this unit is going outdoors, I decided to put it in an enclosure to protect it from the elements. The exact box, method and tools used may vary depending on your application, but for me, I needed to drill a 12mm hole for the cable glands.

Once this was done, I grabbed a Dremel and sanded down the internal ridges so that the nut on the gland could get enough grip.

The next step is to prepare the cable that I’ll be using to attach to the battery of interest. I’m going to use an outdoor water-resistant 2 core pigtail that I got a while ago and use for my Christmas light displays. But realistically, you can use whatever you want.

If your cable is stranded like this, I would recommend crimping on some ferrules to make it easier to use with the screw terminals – but this is completely optional.

After placing the wires through the cable gland and into the box we can connect our board – just be sure to get the right polarity. Finally, we can place it inside the enclosure and secure it with some Velcro / hook and loop tape. Even though this isn't the most secure mounting, it should keep it from flapping around in the breeze as it won't actually move all that much anyway.

But before we close up the box, we need to flash and configure the board if you haven’t already done so. I’ll cover this next.

The Software

Quite frankly, there’s a lot of software used in this project. So I’ll only briefly explain what is going on and skip the minor details.

Generally speaking, the LoRaWAN network configuration, measurement rates, and other configuration items are loaded into memory on the RP2040 at boot up by checking the contents of the flash memory. If the config pin (pin 11) is tied to ground, then it will enter configuration mode where you can access it over serial on a computer. Otherwise, it will average several samples to determine the pin’s voltage before transmitting it over LoRaWAN. Finally, after processing pending events for a predetermined amount of time, it will suffocate the power supply, shut off and wait for the RTC to restart the process. This can all be visualised in a flowchart here.

While this is a rather high level view, there is a lot more going on behind the scenes. Fortunately, for most of our readers, if you wish to do this project at home, you won’t need to edit or compile any code at home. But feel free to do so yourself.

I have created a “uf2” file which you can easily flash to your RP2040-based board and enter the ‘config mode’ that allows you to set options such as the network settings, and measurement intervals etc.

To flash your board, first head to the releases section of my GitHub repo ( and download the latest version. Once downloaded, plug the board into your computer while holding down the boot button. After inserting you can let go of the button and you should see that a mass storage device has appeared in your filesystem. Next, drag/copy the .uf2 file over it. The RP2040 will then flash, unmount and reboot itself. After this is done your board is ready to configure.

To configure your board, first unplug your board, connect pin 11 to ground (as in the photo here) and then power your RP2040 board once again to enter ‘config mode.’

Now you can connect to the microcontroller over the serial port on your computer. You may need to use something like device manager on windows to find which com port the RP2040 has connected to. On macOS and Linux, the device might be something like ‘/dev/tty.usbmodemXXXX’ where the X’s will be some number (and potentially varying length).

There’s a range of different programs you can use to interact with the board such as PuTTY, screen (macOS/Linux) or even the Arduino IDE. I’d recommend the one that you’re most familiar with, but I’ll be using PuTTY. You’ll just need to connect to the board with a baud rate of 115200.

Your “COM” port might be slightly different from mine.

Once connected, you will be presented with a bunch of different options. Take note of the Device EUI as we’ll need that when we’re setting up TTN. The Device EUI is similar to a MAC address used in computer networks – it’s a unique identifier for the hardware.

Note: Just as a side note, the menu might look slightly different to when you’re seeing it as I may have updated it and added extra options.

At this stage, unplug the jumper wire between ground and pin 11. And instead, plug in the board we soldered up earlier, so that we can configure the RTC.

There’s no specific order in which you should configure these, but I’ll go top down. Press ‘0’ on the keyboard to set the LoRa region. It will come up with a set of options for the different region plans.

For us that are in Australia, we’re going to use the “AU915” plan, but for readers outside of Australia, you may need to look up which plan you need to use. After selecting the appropriate region, we can configure the App EUI, or also known as the “JoinEUI.”

You can do this by pressing “1” on the keyboard where you will need to enter in a 64bit unique identifier for the activation. The specific bytes you have here is less important, so you can just put something like “1234567890000000” or whatever you like. After this, it will confirm that you typed it correctly. If it’s all good, press “y” to continue or “n” to re-enter it.

The next thing we need to fill in is the AppKey. But before we can do that, we need to register the end device with TTN – this is where we’ll get the AppKey from. If you haven’t already, you’ll need to create a TTN account.

This can be done by visiting and following the signup prompts. Once you have logged in, you will need press the “+ Add application” button in the top right corner. You’ll be brought to a page like this where you will need to come up with a unique name.

I tend to always prefix my application ID with my username as it needs to be unique globally across TTN’s website. After creating the application, you’ll be brought to a dashboard where you will want to click the “+ Add end device” button to add our end node. In here select the “Manually” tab as we are going to manually register the end device since we created it from scratch.

Up the top, we have the Frequency plan, LoRaWAN version and the regional parameters. For me, I’m going to select the “Australia 915-928 FSB 2” plan as this is used by TTN. To find the LoRaWAN version and regional parameters requires a bit of digging around. But the original LoRaWAN library that we’re using implements version 1.0.4 of LoRa MAC with the RP002 v1.0.3 as the regional parameters version.

A bit further down on the page, we’ll need to paste in the Device EUI that was shown in the serial terminal when we were configuring the device. Similarly, we’ll need to enter the same AppEUI (JoinEUI) in TTN as we did on the device. After this is done, we can press the AppKey’s “Generate” button. You’ll then need to enter that into the device over the serial connection. Just make sure to type it correctly as there’s a lot of characters.

You can optionally set the “End device ID” otherwise you’ll need to record the ID it generates as we’ll need it later when setting up the MQTT connection on Node-RED.

After this, you can press “Register end device” and you’ll have almost everything you need for TTN set up. We’ll come back to TTN so don’t close the tab just yet.

Next, we need to set the pins that we’re wanting to measure on. Press “3” inside the serial terminal and you will be asked which pins you want to measure on. For this demo, I’ll only be using the first pin, but you are welcome to use any of the others.

You just need to press either “y” or “n” to enable or disable the pin. After this, we’ll set the sleep duration of the device – which directly affects how often we will take a measurement. There is no inherent right or wrong value, but do keep in mind the TTN network's fair use policy and any applicable laws and regulations regarding the duty cycle of the transmission in your country. Generally speaking, you should aim for no less than 20 minutes to keep it in line with the TTN's community guidelines.

Finally, we want to set the processing events timeout – that is how long after we finish sending the payload do we process the events. Something like 15 seconds should be sufficient, but if you run into issues later on (such as it not sending properly), you can always change this.

After this, we can press “q” to quit config mode. The device will then save the configuration to flash and attempt to connect to the LoRaWAN network where you start to see some data come up in the TTN dashboard.

Once we have the device all configured, we can now place the board in the enclosure and connect it up to our battery.

After the hardware has been set up, it’s time to set up the web dashboard that we’ll use to monitor the battery voltage. There’s a plethora of different options at our disposal here. Perhaps one of the simpler solutions is to have a web interface that we can access from a PC.

For this, we’ll use a Raspberry Pi running Grafana, InfluxDB and Node-RED. Feel free to use something other than Raspberry Pi if you’re having trouble sourcing one, or prefer to use something else.

For convenience, I’ve created a docker-compose script with all the needed containers pre-setup. So strictly speaking, the actual platform is less important – as long as it runs Docker, it will be fine. But for those who want to do it the slightly more manual way, I’ll also briefly run through the process.

Before cloning the docker scripts, it’s a good idea to update and upgrade the packages using the following command.

sudo apt-get update && sudo apt-get upgrade -y

Once that has been done, for those wanting to use the preconfigured docker scripts, you’ll need to clone my repository using

git clone

This assumes you have git, docker and docker-compose installed. If not, you can install them with the following commands.

sudo apt-get install git docker docker-compose -y
sudo usermod -aG docker $USER

You’ll then need to reboot after installing docker. There are more instructions available in my repository to get you started. Once cloned, you will need to run the following commands.

This will begin downloading and start building the containers. This can take a few minutes, so might be good to take a short break while you wait.

Once the build process has completed, open a browser up, and head to the IP address of your Raspberry Pi (or server) with the port of 1880 - for example, You can find the IP of your Raspberry Pi by either checking in the DHCP leases in your router, or using the following command on the Pi:

hostname -I

This will load up the Node-RED dashboard which is where you will find all the logic in our application.

If you’re using the provided docker image, you’ll find a bunch of preconfigured nodes all linked together. For those that wish to use an existing node-red installation or for those with a blank workflow, you’ll need to add the flow I created. You can download the JSON flow file on the DIYODE website.

All of the nodes have been pre-configured except for the MQTT one as you’ll have different credentials. If you double-click the “TTN (CHANGE ME)” node the following view should come up.

There’s 4 things we need to change in this menu. But before we do, we need to hop over to the TTN’s dashboard to obtain the MQTT details.

In the side bar on the far left, under “Integrations” click the MQTT tab. This will take you to a page with the connection details for the MQTT server that we can connect to.

I have prepopulated the Australian server’s address. However, if you’re outside of Australia, or are using one of their other servers, you’ll need to take note of the “Public TLS address” as you’ll need to change the server in Node-RED. The details we need here is the username and password.

Press the “Generate new API key” button – this will create the password that we’ll put into Node-RED, so either write that down or copy it to clipboard.

Back to Node-RED, press the pencil icon next to the dropdown that says “TTN MQTT” to open up the MQTT broker configuration as shown here.

Here is where you can change the server address if you aren’t using the Australian one. But what we want to do is set the username and password. To do this, hit the “Security” tab, and then populate your credentials that we just got from TTN into their respective fields.

From here press “Update” and it will take us back to the previous slide-out. This is where we’ll change the topic. Replace “” with the username that we just used before, and then change “” with the “End device ID” that you either entered in or that TTN generated for us earlier. After this is all filled out, you can press “Done” and then press the red button up the top right-hand corner that says “Deploy” to set all the configurations and start the flow.

If everything has been configured correctly, you should be able to now navigate to the Grafana page by entering the IP address of your Pi at port 3000 – eg, You will be brought to a login page.

After logging in with the default login details of username: admin and password: admin, you will be brought to a page to enter a new password. After either setting a new password or pressing “skip” you will be brought to a dashboard page.

From here, click the dashboards button and then select the “Browse” option. A “Battery monitor” dashboard should appear (see below) and if you click it you should be taken to the dashboard where it has the data – you may have to wait for some time to pass for data to start populating.

For those who aren’t using the docker compose script, then you’ll need to create a dashboard for the data to be displayed. To do this, you’ll need to add an Influx datasource and then configure the query in Grafana to look like the screenshot here.

That’s it! We’re done. After some time you should have a stylish graph that looks like this (this is 1 week’s worth of data).

By default, Grafana will scale the graph automatically to fit all of the values. To make it visually more representational of what you're measuring, it could be better to manually define the y-axis bounds if you know the general range of numbers you expect.


Some of you may run into issues launching the docker-compose script. It’s likely due to having other similar containers (or even other programs) that are using the same port that the containers want to bind to. There’s a couple of different options here. The easiest solution is to manually change the ports in the docker-compose file to something that isn’t currently been used by your Pi. Perhaps the better solution is to find out what is using the port on your machine and potentially use the pre-existing version.

If you can’t access the Node-RED and Grafana dashboards, it might be worth checking to see if docker and the containers are running. Sometimes they stop running – this mainly occurs after a reboot. If you are using the docker-compose script I supplied, the containers are set to restart automatically unless stopped by you the user.

Another issue you can have is that if the voltages you're detecting are close to zero or significantly lower than you anticipated. Double check that all your connections are made and that specifically your resistor dividers are connected and are correct – this caught me out, it’s easy to forget to come back to bridging solder pads together.

Another thing that is worth mentioning is that if you’re finding that your device isn’t turning on, there could be a few different things at play. The first one is that the RTC has lost its settings or may have not been set correctly. Another thing you could check is that you have the correct MOSFETs in the correct places. You may even want to manually ground the gate of the P-channel MOSFET to see if it turns the board on.

For those that find their board not wanting to connect to TTN, perhaps the best thing to test is the default example application. Head to the pico-lorawan repository (as linked before) and download the latest version of the code. After configuring the connection details, compile it and flash it to your board. If there is still no data, you can even try connecting to it over serial to see if there are any LoRaWAN connection issues.

As for the preconfigured dashboard in Grafana, you may need to re-create the query if the dashboard doesn’t show any data after a while. To do this, you can either reselect items in the query, or blow the query away and create your own according to the query structure I gave above.

Where to from here?

There is so much more you could do with this project – I like to think of this as just a framework for you to add on and experiment with. Straight out of the box, you’re able to measure multiple voltages (assuming they share a common ground). All you need to do is add the necessary voltage divider and configure it in the settings.

This project only measures voltage, which really isn’t enough for proper battery monitoring. Ideally, we’d also be collecting current information. So adding this would provide a more accurate monitoring system and would allow you to calculate the power flowing through the battery. You could use something like the ACS712 current sensor and measure the current going through a cable.

The sensor outputs a voltage which is directly proportional to the current – makes it easy to use with our monitor. You could then easily convert the values in Node-RED as we did for the other voltages. I may even go down this path in the near future as it would really help me understand what is going on with my setup, but for now, I’ll leave it up to you to add this feature.

Earlier I mentioned that I intend on using it to monitor the battery for my driveway lights, another step I could take is to factor in some wireless light switch, or even just a simple (and updateable over-the-air) timer switch. That way I could conserve battery life if the forecast for the next couple of days looked to be non-ideal, or if I only wanted the lights to be on for a period of time – maybe the battery lasts too long and you want the lights to turn off after some time.

Another task I have skipped for the time being, and that could be improved upon is the way that the node connects to the network. Currently, I’m re-joining the network after each boot. This is far less than ideal as it takes a decent amount of time and resources to connect and digs into our “air time.” Instead, what you can do is save the OTAA session and credentials to flash and then shut off.

That way when you power back up, you can restore the state and don’t need to fully re-join. I may add this feature later, but in the meantime feel free to contribute by creating a pull request on GitHub. Having this feature could mean our overall air time is lower which would allow us to increase the measurement frequency.

Maybe you might like to present the data in a different way. Currently, it’s only going to work on the local network. You could make your own statistics website viewable from outside the local network or even import the data into something like Home Assistant. Maybe you want to make a standalone website that presents these graphs. You could even use another device such as an ESP32 and display it on a character display.

The sky is really the limit!

LoRaWAN Battery Monitor - Part 1