ATtiny84 Low power LoRa node

** 2021-04-07 ** Update: Look at the blog for information on how to use this node with The Things Stack V3. The code is ready for The Things Stack V3, please read the comments in the code and

** 2020-08-17 ** Update: Due to pin numbering the original code of 2018 does not work on PlatformIO toolset. The code is changed and adapted to function with the current version an arduino-attiny library. The changes are only made in the OOP version of the code on GitLab.

In this post I will show you the development of a Low Power LoRa node with a ATtiny84. A lot of thanks to the guys on The Things Network forum. I took their code for ATtiny85 and modified it to use it for a ATtiny84. I used this processor because I was familiar with it and has more IO pins.

Main modules/electronics used:

  • ATtiny84A microprocessor
  • BME280 sensor
  • RFM95W LoRa module

Technical specifications:

  • 4.8 microAmpere in sleep mode (3.3V)
  • 100mA @51 ms sending data SPF7
  • About 2.2-3.6 V power supply (Lithium Battery)
  • Measurement of Supply voltage, Temperature and Humidity in current version of the software.

Picture of the latest version:

Final version of the node

I used 675 Zinc-Air Batteries to create a real small LoRa node. Here a picture to compare the size to a 9V battery:

The PCB size is 45 x 20 mm. Maximum height is about 18 mm without housing.

The schematic:

** NEW ** 2018-05-15: OOP code at

The schematic and PCB design can be found at

The total cost (typically Dutch):

Device Shop/webshop Price
ATtiny84  €       2,90
RFM95W  €       4,60
BME280 (inclusief header pins-6 voudig)  €       2,99
Printplaat LJK1801 EasyEDA  €       1,98
Batterijen (2x) 675 Zink Air Kijkshop  €       0,67
Batterij-veren  €       1,10
IC-voet 14 pens  €       0,16
C 100nF, raster 5 mm MKT  €       0,15
C 470uF, 10V, 8,2x12mm axiaal  €       0,10
Header-6pin female  €       0,25
Header-2pin male  €       0,03
Dupont-2pin female krimp  €       0,10
3D print matriaal behuizing    €       0,23
Totaal    €     15,25

Current measurements:

Remember to remove the resistor on the BME280 to reduce current in sleep mode. Here (not) shown in second place from the top at the (original) 5 SMD parts.

The calculations I did to get the lifetime. Please correct me if I am wrong:


  • 4.8 uA in sleep
  • 100 mA @ 51 ms pulse every 5 minutes.

Power used in a year:

rest: 4.8 * 10E-6  A * 24hours * 365.25 days = 0.04104 Ah = 41.04 mAh per Year

sending: 100 *E-3 A * 288 measurements a day * 365.25 days * 51 * 10E-3 seconds / 3600 seconds in an hour = 0.149022 Ah = 149.022 mAh per Year.

Total 190 mAh per Year.

Useable time:

675 Battery (Zinc-Air):  640 mA => 3.37 Year

LS14250 Battery (Lithium): 1200mA => 6.3 Year

LS14500 Battery (Lithium): 2450mA => 12.9 Year

(This is incredible!, I do not believe it)


I am now testing a few nodes: outside, in the freezer (-20 degrees Celsius) and room temperature with different batteries.

Inside (box) and outside closure:

I designed and printed this closure myself (3D print). You only have to add 2x M4 x 60mm bolts and 2x M4 nuts. I made the design public available: You have to print the mid-section a few (8) times. I learned that it is called Stevenson screen. My design has the looks but not the scientific usability :smile:

31 thoughts on “ATtiny84 Low power LoRa node

  1. GB

    I love this absolutely brilliant design. We are going to use these for establishing sensors around our farm.

    However, your schematic indicates a 470uF 6,3V D3x3,5 capacitor, while your itemization on this page says 470uF 10V D8,2×12. Could you please clarify?

    Could you also confirm the other capacitor? Would this would be appropriate?

  2. Leo Post author


    Thanks for the complements, great to hear that you’re gonna use my design. Have fun with it!

    About the 470uF capacitor:
    Because of the 3.3 V working voltage a 6,3 Volt Capacitor would be enough. I bought a 10 V capacitor because a 6,3 V was not available or the size was not appropriate for my (physical) design.
    You may choose yourself what size or voltage you want to use. The capacity is also arbitrary, I did not make any calculation. Ik know when the RFM95W is sending data It wil draw 100mA in 50uSeconds.
    I guessed that will be heavy load for the battery, so I decided to add this capacitor to catch this pulse a bit, and to prevent the voltage to drop to much near the end of the lifetime of the battery.

    The 100nF capacitor you mentioned is fine. This 100nF capacitor is a (default) interference suppression capacitor for high frequencies.


  3. ehmet

    wonderful job conventions … I would use it for communication between 2 lora, so if you want to take out the thing network, what can I do to tell you step by step … thanks …

  4. marko

    Cheap but neat, I like it. I think the 675 battery with a much higher leakage current (selfdischarging) and narrow temp. working range can’t reach this numbers.
    To even lower current consumption heres my thoughts:
    – ordinary 470uF elko can draw several uA of current (leakage), eg. Nichicon KL series (very low leakage) only up to 0.2uA (200nA)
    – ATinny84 sleeping with wake up on external pin signal draw only ~0.5uA ( ), watchdog is disabled for the external hardware timer eg. TPL5110 with operating current 35nA
    – last but not least, check please this interesting document from TI:
    maby Lora module can do same trick at 2.1V with TPS62730 DC-DC converter (30nA at sleep/bypass mode) and TX current (100mA at 3.3V) will drop by nearly 30% without any penalty like eg. max efective TX RF power output

    Correct: ATtiny85 sleep mode and wake on pin change: >0.2uA at 3.3V, >0.1uA at 2.1V

  5. Leo Post author

    When you want tot use Lora as a peer-to-peer connection it is better to use other examples.
    The Things Network LoRa is based on the LoRa based transmit technics and the LoRaWAN layer.
    The LoraWAN layer is responsible for encrypting data and authentication etc.
    This LoRaWAN layer uses also a lot of recourses of the microcontroller.

    For Peer-to-Peer connections you do not have to use this layer, It is easier to connect, using only the LoRa Transmit technics.

    An example is available here, it uses an ATmega32u4 and RFM95:

    You can use the code to use it as starting point to program an ATtiny84 and RFM95.

    I hope this information will help you to solve your problem.


  6. Leo Post author

    It seems you’re an expert on this area (leak current/minimal power). Thank you very much for your comments on this!
    I’ll study the documentation an use some idea’s in my next designs!

    I’m now studying on Low power ARM processor (STM32L series) to make the node smaller (SMD design) and powerful processing possibilities.


  7. marko

    I’m definitely not an expert but thank you 🙂

    STM32L series is a very good choose, these parts are maybe best-in-class for now in power efficiency but i think some new optimised 8-bit MCUs still can beat them in some simple tasks that requires ultra low current consumption.

    You may already know that, but anyway I forgot to mention that ATtiny84A instead of ATtiny84 is a power-optimised version:

    sorry about that but 2nd correction on: “ATtiny85 sleep mode and wake on pin change: <0.2uA at 3.3V, <0.1uA at 2.1V" (less than <)

  8. Gerhard Peter

    Can i integrate this device in TTN seamless, or is it a Point-tp-point device. It would be nice, if TTN integrattion is possible. Thx. g.

  9. Leo Post author

    You can integrate this device in TTN seamless. It uses ABP Activation Method.
    I’ve now 4 of these devices running on different batteries (Saft LS14250 and Saft LS14500).
    One of them is placed in a freezer (-20 degrees Celsius).


  10. Kim Warwick-Oliver

    Hi Leo. Your design works well. I am trying to get pressure data out so I can measure height. Then also voltage. The calculations for pressure seem more complicated and I can’t fit it in. Changing to just one frequency and removing other stuff I get withing 30 bytes of fitting. Did you get pressure to work?
    Just sending raw bytes and calculating elsewhere is beyond my ability.

  11. Henk

    Hello, verry interesting.

    I looked at the gitlab links but was not able to find the complete *ino file’s
    For me it seems that there are only library’s but no complete code for a ttn node

    Did I missed something? A tip is apreciated.

    Kind regards, Henk

  12. Leo Post author

    Hello Marco

    I put Vcc in the array and send it to monitor the power consumption or status of the battery, that you will understand.
    The first reason I do not send the pressure, is because I do not need that information. I have 1 pressure sensor on another device, and in my surrounding the pressure is equal (Holland, very flat…)
    But, there was another guy who want to check on his sheep walking uphill and downhill, and he wants to measure pressure to get the height.

    We both found out that the memory of the ATtiny84 is not capable to hold the code to calculate the pressure.
    It seems that every pressure sensor BMP280 has calibration data in it. The code uses this data to recalculate the actual pressure and this is a big calculation. The code wil be about 1k more than the 8k available in the ATtiny84.
    Thats was a disappointment.
    There are three ways to resolve this problem:
    – use an other sensor
    – get the calibration data and just send the raw data. Calculate the actual pressure on the server side (Thats the solution this guy is gonna use)
    – use an other processor (thats what I’m trying to do, using a ARM stm32l151 or 051, I’m now testing and making development boards).



  13. Leo Post author

    Hello Henk,

    You can find the source code in main.cpp in the src directory.
    I’m using PlatformIO as development environment, that’s the reason why you do not see a .ino file.
    I think you can copy the source code of this main.cpp in a new Arduino project and you have to make sure you can use the libraries that are in this project.



  14. Leo Post author

    Just for other readers of this post:

    We both found out that the memory of the ATtiny84 is not capable to hold the code to calculate the pressure.
    It seems that every pressure sensor BMP280 has calibration data in it. The code uses this data to recalculate the actual pressure and this is a big calculation. The code wil be about 1k more than the 8k available in the ATtiny84.
    Thats was a disappointment.
    There are three ways to resolve this problem:
    – use an other sensor
    – get the calibration data and just send the raw data. Calculate the actual pressure on the server side (Thats the solution Kim is trying to use)
    – use an other processor (thats what I’m trying to do, using a ARM stm32l151 or 051, I’m now testing and making development boards).



  15. btrek

    Hi, why did you connect the RFM95 to VCC and GND before the two capacitors?


  16. Simon

    Hi Leo, this is a really great project. Thanks a lot for sharing this very detailed tutorial.
    I was able to rebuild one of these sensors exactly like you described.
    Unfortunatly i a allway receiveng only one Packet over my Gateway. As far as i understood if using ABP there should be some kind of communication between the Device and the Gateway before sending the Data. I receive a Packet every 5 Minutes an 7 Seconds like described in the Code. With a really short Payload for example “0BA00C2C0D57”
    Sorry for the Questions, but does this Payload includes the Temperature and the VCC ?

    What application do you use for Monitoring the Data, i was thinking about to push this data to an Influx DB and present it in Grafana.
    Would be really great if you could help me how to get the Temperature from the Payload.

    Thanks a lot for this great project 🙂

  17. Leo Post author

    Hello Btrek,

    In the schematic this is not drawn on purpose before the two capacitors, it just because I did not make a very good drawing.
    In the PCB the RM95 is “behind” the capacitors, by the way.


  18. Leo Post author

    Hello Simon,
    Thanks for the complements. I will try to answer your questions.
    ABP, there is no communication back from the gateway to the device. The device only sends its packet to the air. The advantage is that the time NOT in sleep mode is very short.
    So the gateway should receive 1 packet every 5 minutes (about). The counter for every packet is increasing. After a reset (unplug the power/battery and shortcircuit the power pins on the board, otherwise the Condensator will keep the power on) the counter will be set to zero.
    The payload includes the VCC, temperature and humidity.
    First of all you should extract the bytes from the payload. You can do this in different ways:
    Do it at The Things Network at the PAYLOAD FORMATS place in your application:

    Put in this code:

    function Decoder(Data, port)
    var vccVoltage = (Data[0] << 8) | Data[1]; var temp = (Data[2] << 8) | Data[3]; var hum = (Data[4] << 8 ) | Data[5]; return{ vcc: vccVoltage temperature: temp /100, humidity: hum / 100, } } At your endpoint you can use this output to process further. You can also decode it at your endpoint, but then you have to use more code. I can give you a Java example if you want, but this requires more programming skills. I hope you have enough information to continue. With kind regards, Leo.

  19. Gert de Vries

    Hi Leo, what if you would use an Arduino Pro Mini for increased flash memory? Its power consumption can also be brought down to a few uA.
    The lmic library uses most of the ProMini memory, so your code could be an improvement. However, is it sending over a single channel?

  20. Daniel

    World this Setup also work with an hc–srf05 Sensor for Distanz measuring?

  21. Leo Post author

    Hello Daniel,

    I think this could work with a hc-srf05 distance sensor. You have to replace the BME code with code/driver for the distance sensor.

    With kind regards,

    Leo Korbee.

  22. Leo Post author

    Hi Gert,

    I have used an Arduino Mini in my first project. The reason I did not continue with this board is the form factor. I wanted to make a PCB as small as possible.
    Now (if I have time for this) I try to make it even smaller with a ARM STM32 microcontroller. The first tests are hopeful. The cons are that you have to solder SMD components on the PCB.
    But that is a nice challenge.

    My project is sending over multiple channels. You can change this if you want.
    The code you have to look for is this:

    // EU863-870 specifications
    switch (TCNT0 % 8)
    case 0x00: //Channel 0 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
    case 0x01: //Channel 1 868.300 MHz / 61.035 Hz = 14226264 = 0xD91358
    case 0x02: //Channel 2 868.500 MHz / 61.035 Hz = 14229540 = 0xD92024
    // added five more channels
    case 0x03: // Channel 3 867.100 MHz / 61.035 Hz = 14206603 = 0xD8C68B
    case 0x04: // Channel 4 867.300 MHz / 61.035 Hz = 14209880 = 0xD8D358
    case 0x05: // Channel 5 867.500 MHz / 61.035 Hz = 14213156 = 0xD8E024
    case 0x06: // Channel 6 867.700 MHz / 61.035 Hz = 14216433 = 0xD8ECF1
    case 0x07: // Channel 7 867.900 MHz / 61.035 Hz = 14219710 = 0xD8F9BE
    // FSK 868.800 Mhz => not used in this config
    // 869.525 – SF9BW125 (RX2 downlink only) for package received


    The TCNT0 gives a random number and with modulo you can randomize 0-7.
    You can change this to switch to one or more frequencies.

    With kind regards,

    Leo Korbee.

  23. Philippe Jimenez

    Hello Leo,
    Great work ! I use this design in my house and the sensors work fine. Recently, I did a new sensor and put it outdoor, so when the temperature is negative, I didn’t received a negative result but a value around 650… For example, I have this data :
    Time Room Batterie Temp Humidity
    1610353844 1 3.827 654.98 58.64
    1610354142 1 3.827 0.07 57.87
    1610354440 1 3.814 0.15 58.08
    Do you know where is the problem ?
    Thank you.

  24. Leo Post author

    Hello Philippe,

    Thanks, is always nice to see other people use my design.
    Strange behaviour, but explainable:

    The temperature is send with a unsigned int 16 bits x 100.
    So 20.05 degrees will be send as 2005
    Due to 16 bit the maximum number/temperature will be 65536 unsigned.

    To get negative numbers the Most Significant bit is used as negative/positive sign. So these 16 bits can represent -32768 to 0 to 32767.

    The problem you have is the conversion back: you should check the MSB if it is a negative number and the subtract 655.36 (65536/100).

    In your case: 654.98-655.36 = -0.38 degrees.

    I receive my data with a Java API and use this snippet to decode it:

    // temperature
    int temperature = (byteData[2] << 8) + toUnsignedInt(byteData[3]); float tempFl = temperature/100F; temperatureStr = String.format("%.2f", tempFl); The MSByte is shifted to the left and hence has the sign bit in it. The Java int is signed. I think you have to check your decode code. With kind regards, Leo.

  25. Pierre

    Hello Leo,
    Where can I find a multimeter like you have on the picture above?

    Being new at this I bought one on sale to check and discover that the order of magnitude between uA and mA reading can be 100 times. At this point it might as well write useless reading. It seems that multimeters are marketed like cars.

    I am trying to read the consumption of the BME280 when sleeping during forced mode. the multimeter should be in series with the sensor. I could not add a picture of my contraption which is not like you made. Reading is 0.18mA which seem to be a lot. I will continue to troubleshoot.

    Thank you very much for sharing

  26. Leo Post author

    Hello Pierre,

    The multimeter I used is a Unigor 6e original from Goerz. It’s made around 1970-1980 and I used it at school when I was 16/17 years old.
    I think I bought it 20 years ago on an army dump shop. Maybe you can find it somewhere on the internet. The advantage of an analog meter is that you can see the spikes by moving needle.

    However I use now also digital meters. I have good experience with the Owon OW18B multimeter, also for low currents on my projects.
    For about €40-50

    On the BME280, you have to check the pins of your microcontroller If they are low or high on power down/sleep mode. On the BME module some lines are pulled up or down by a 10k resistor. You can check this by setting the module in sleep/low power mode and remove the signal pins (not the power and ground) and measure the current.
    In some of my projects with the BME280 I set the pins to analog input after setting the BME280 to sleep mode to reduce power.

    I hope this will point you in the right direction,

    With kind regards,



    Hi Leo,
    Very interesting project.
    Only a question:
    have you delevopped a LORA RECEIVER to receive locally this sensors ???
    Many thanks in advance.

    Best regards

    Mauro IK1WVQ

  28. Mauro IK1WVQ

    “LOCAL RECEIVER” = module RFM9x + microprocessor + serial output of data received .

Leave a Reply

Your email address will not be published. Required fields are marked *