Solar-powered remote sensor node with LILYGO TTGO LoRa32 board, mini solar panel, 18650 battery holder, and AHT20 sensor mounted outdoors

Intermediate

Build a Solar-Powered Remote Sensor Node

SensorsWirelessIoT

Take the LoRa Sensor Node off the wall entirely: a small solar panel and battery keep it running indefinitely outdoors, reporting real environmental data over long-range radio with no cable in sight.

4 real parts included

Total for this kit: 1,435.00 ฿

Doesn't include any order discount you may get at checkout.

What you'll need

Project Goal

This project extends the existing LoRa Sensor Node build with real independence: a solar panel keeps a battery topped up during the day so the node can report environmental readings from anywhere outdoors, a shed, a garden, a fence line, with no power cable required at all.

What the Controller Does

On a long sleep-wake cycle to conserve battery, it reads the sensor, transmits the reading over LoRa radio, and goes back to sleep. Power efficiency matters far more here than in a wall-powered project, since every wasted milliamp is battery life that solar charging has to make back the next day.

What the Sensor Does

It reports real temperature and humidity on demand over I2C, the same sensor already proven in the wall-powered version of this build.

What the LoRa Radio Does

It transmits each reading over long-range radio back to a base station, the same long-distance link used by the original wall-powered node, unaffected by whether the transmitting end is battery or mains powered.

What the Solar Panel and Battery Do

The panel trickle-charges the battery during daylight hours, and the battery is what actually powers the node around the clock, including overnight when the panel produces nothing. Be honest with yourself about the panel's real output: small panels like this commonly deliver meaningfully less current in real outdoor light than their printed wattage rating suggests, especially on overcast days or when not aimed directly at the sun. Size the battery generously and treat the panel as a slow top-up, not a guaranteed full recharge every single day, and verify actual charge current with a multimeter before trusting the node to run unattended for long stretches.

Software and Library Concepts

Start from the working wall-powered LoRa Sensor Node code, then add deep-sleep between readings, this single change has the biggest impact on how long the battery actually lasts.

Testing and Troubleshooting

  • The battery slowly drains even with the panel connected, measure actual charge current in real outdoor light with a multimeter rather than assuming the printed wattage, then lengthen the sleep interval between readings if the panel genuinely can't keep up.
  • Readings stop arriving overnight or on cloudy days, that's expected if the battery capacity is undersized for the local weather, this is a sizing problem, not a wiring fault.
  • No charging at all, confirm panel polarity and that it is genuinely receiving direct, unobstructed daylight, not just bright shade.

Optional Upgrade

Add a battery voltage reading to the transmitted data itself, so the base station can see the node's own power health remotely instead of requiring a physical visit to check on it.

Wiring

  • AHT20 VCC → LILYGO TTGO LoRa32 3V3
  • AHT20 GND → LILYGO TTGO LoRa32 GND
  • AHT20 SDA → LILYGO TTGO LoRa32 GPIO4 — shares the board's onboard OLED I2C bus (SDA=4/SCL=15); safe because AHT20's I2C address (0x38) doesn't collide with the OLED's SSD1306 address (0x3C)
  • AHT20 SCL → LILYGO TTGO LoRa32 GPIO15
  • 18650 Battery Holder (+/−) → LILYGO TTGO LoRa32 onboard JST-PH 2-pin battery connector (or the board's BAT/5V + GND pads if it has no JST connector on your revision) — this is what actually powers the board from the batteries
  • 6V Mini Solar Panel (+/−) → do not wire directly to the battery holder/cells — see NOTES

This build assumes a TTGO LoRa32 V1 board, which has a well-documented fixed onboard pinout for the LoRa radio (SX127x) and OLED. V2/V2.1 boards moved some of these pins (notably the LoRa CS/RST/IRQ lines), so confirm your exact revision against its silkscreen/schematic before trusting these `#define`s.

Honest safety note on the solar/battery wiring: the parts list here is a 6V ~1W solar panel and a bare 2-slot 18650 holder with a switch — no charge controller IC is listed. Wiring a raw solar panel straight to bare 18650 cells has no overcharge, overcurrent, or reverse-current protection, and can overcharge/damage or even vent the cells, especially on a sunny day when the panel's open-circuit voltage can exceed what a single Li-ion cell should ever see. Many TTGO LoRa32 V1 boards do include an onboard charge-management chip (commonly TP4054-class) feeding their JST battery connector, but that circuit is designed for charging over the board's USB port, not for an unregulated 6V panel dumped onto the battery leads. The technically correct and honest solution: add a small solar/LiPo charge controller module (e.g. a TP4056-style or dedicated solar charge controller) between the panel and the battery, and only feed the controller's regulated battery output into the holder/board. Treat "panel + bare cells + switch" alone as not a safe standalone charging circuit, and call this out to the customer rather than pretending otherwise.

The code below focuses on the part of the build that's fully real and verifiable with the listed parts: reading the AHT20 over I2C and transmitting the reading via LoRa using the `LoRa` library by sandeepmistry, a standard, genuine library for SX127x radios. It sleeps between sends to conserve battery — important for a solar-powered remote node.

Wiring Diagram

VCC → 3V3 GND SDA → GPIO4 SCL → GPIO15 LILYGO TTGO LoRa32 AHT20 18650 Battery Holder

Starter Code

#include <Wire.h>
#include <Adafruit_AHTX0.h>
#include <SPI.h>
#include <LoRa.h>

// TTGO LoRa32 V1 onboard pinout — confirm against your board's specific
// revision/silkscreen if anything doesn't match.
#define OLED_SDA   4
#define OLED_SCL   15
#define LORA_SCK   5
#define LORA_MISO  19
#define LORA_MOSI  27
#define LORA_CS    18
#define LORA_RST   14
#define LORA_IRQ   26

// Set to the frequency your LoRa radio module/region uses, e.g. 915E6 (US),
// 868E6 (EU), 433E6 — check the radio module's marking/your local regs.
#define LORA_FREQUENCY 915E6

Adafruit_AHTX0 aht;

void setup() {
  Serial.begin(115200);
  Wire.begin(OLED_SDA, OLED_SCL);

  if (!aht.begin()) {
    Serial.println("AHT20 not found — check wiring/I2C address");
    while (1) delay(1000);
  }

  SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
  LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ);

  if (!LoRa.begin(LORA_FREQUENCY)) {
    Serial.println("LoRa init failed — check wiring/frequency");
    while (1) delay(1000);
  }
}

void loop() {
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);

  LoRa.beginPacket();
  LoRa.print("T:");
  LoRa.print(temp.temperature);
  LoRa.print(",H:");
  LoRa.print(humidity.relative_humidity);
  LoRa.endPacket();

  Serial.printf("Sent T=%.2fC H=%.2f%%\n", temp.temperature, humidity.relative_humidity);

  delay(60000); // once per minute — tune for your power budget
}

Not sure about a step? Ask us