RFM69_LPL firmware for Nathan Chantrell's TinyTx with ATtiny84

I created a GitHub repository for RFM69_LPL versions of TinyTx firmware sketches. The original JeeLib-based firmware sketches and the ATtiny84-based TinyTx board were created for the OpenEnergyMonitor ecosystem by Nathan Chantrell.

TinyTX3_Front_Back

So far I’ve completed the TinyTx_DS18B20 temperature node sketch. It gives a good starting point for anyone wanting to work with a TinyTx board and communicate with the new RFM69 LPL radio format.

Here is that sketch.

/* TinyTx_DS18B20_LPL
 * TinyTx Temp Sensor with RFM69_LPL radio library
 * Brandon Baldock August 2023
 * 
 * This is the original TinyTx sketch by Nathan Chantrell, modified to work with the OpenEnergyMonitor fork of the
 * RFM69 libarary from Felix Rusu of LowPowerLab. //https://github.com/openenergymonitor/RFM69_LPL
 * 
 * I used the OpenEnergyMonitor default encryption key (89txbe4p8aik5kt3) and network (210). 
 * I changed the ACK_TIME definition to the RFM69 default "retryWaitTime" of 30 (originally 10).
 * I changed the RETRY_LIMIT definition to the RFM69 "retries" default of 2 (originally 5).
 * I removed the RETRY_PERIOD definition. How soon to retry is not user-defined in RFM69.
 * I removed the waitForAck() function because this is handled in RFM69 by sendWithRetry.
 * 
 * Use Spence Konde's ATTinyCore to compile the firmware.
 * I switched to the ATTinyCore pin notation (using "PIN_PA0" rather than "10", for example) to reduce confusion.
 * I have tried to leave everything else untouched.
 */

//----------------------------------------------------------------------------------------------------------------------
// TinyTX - An ATtiny84 and RFM12B Wireless Temperature Sensor Node
// By Nathan Chantrell. For hardware design see http://nathan.chantrell.net/tinytx
//
// Using the Dallas DS18B20 temperature sensor
//
// Licenced under the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) licence:
// http://creativecommons.org/licenses/by-sa/3.0/
//
// Requires Arduino IDE with arduino-tiny core: http://code.google.com/p/arduino-tiny/
// and small change to OneWire library, see: http://arduino.cc/forum/index.php/topic,91491.msg687523.html#msg687523
//----------------------------------------------------------------------------------------------------------------------

#include <OneWire.h> // http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip
#include <DallasTemperature.h> // http://download.milesburton.com/Arduino/MaximTemperature/DallasTemperature_LATEST.zip
#include <JeeLib.h> // https://github.com/openenergymonitor/RFM69_LPL
#include <RFM69_LPL.h>      //https://github.com/openenergymonitor/RFM69_LPL
RFM69 radio;

ISR(WDT_vect) { Sleepy::watchdogEvent(); } // interrupt handler for JeeLabs Sleepy power saving

#define myNodeID 1        // RF12 node ID in the range 1-30
#define network 210       // RF12 Network group
#define freq RF12_433MHZ  // Frequency of RFM12B module

#define ENCRYPTKEY    "89txbe4p8aik5kt3" //OpenEnergyMonitor sample encrypt key is 89txbe4p8aik5kt3

#define USE_ACK           // Enable ACKs, comment out to disable
#define RETRY_LIMIT 2     // Maximum number of times to retry
#define ACK_TIME 30       // Number of milliseconds to wait for an ack

#define ONE_WIRE_BUS PIN_PA0    // DS18B20 Temperature sensor is connected on D10/ATtiny pin 13
#define ONE_WIRE_POWER PIN_PA1  // DS18B20 Power pin is connected on D9/ATtiny pin 12

OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance

DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature

//########################################################################################################################
//Data Structure to be sent
//########################################################################################################################

 typedef struct {
      int temp; // Temperature reading
      int supplyV;  // Supply voltage
 } Payload;

 Payload tinytx;

//--------------------------------------------------------------------------------------------------
// Send payload data via RF
//-------------------------------------------------------------------------------------------------
 static void rfwrite(){
  #ifdef USE_ACK
  //sendWithRetry(uint16_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=RFM69_ACK_TIMEOUT);
   radio.sendWithRetry(0, (const void*)(&tinytx), sizeof(tinytx), RETRY_LIMIT, ACK_TIME);
   radio.sleep();              // Put RF module to sleep
   return;

  #else
   radio.send(0, (const void*)(&tinytx), sizeof(tinytx), false);
   radio.sleep();              // Put RF module to sleep
   return;
  #endif
 }

//--------------------------------------------------------------------------------------------------
// Read current supply voltage
//--------------------------------------------------------------------------------------------------
 long readVcc() {
   bitClear(PRR, PRADC); ADCSRA |= bit(ADEN); // Enable the ADC
   long result;
   // Read 1.1V reference against Vcc
   #if defined(__AVR_ATtiny84__) 
    ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84
   #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  // For ATmega328
   #endif 
   delay(2); // Wait for Vref to settle
   ADCSRA |= _BV(ADSC); // Convert
   while (bit_is_set(ADCSRA,ADSC));
   result = ADCL;
   result |= ADCH<<8;
   result = 1126400L / result; // Back-calculate Vcc in mV
   ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power
   return result;
} 
//########################################################################################################################

void setup() {
  
  radio.setPins(PIN_PB1,PIN_PA5,PIN_PA6,PIN_PA4); // (SSpin, MOSIpin, MISOpin, SCKpin)
  radio.initialize(freq,myNodeID,network);        // Initialize RFM12 with settings defined above 
  radio.encrypt(ENCRYPTKEY); 
  radio.sleep();                                  // Put the RFM12 to sleep

  pinMode(ONE_WIRE_POWER, OUTPUT); // set power pin for DS18B20 to output
  
  PRR = bit(PRTIM1); // only keep timer 0 going
  
  ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power

}

void loop() {
  
  digitalWrite(ONE_WIRE_POWER, HIGH); // turn DS18B20 sensor on
  
  //Sleepy::loseSomeTime(5); // Allow 5ms for the sensor to be ready
  delay(5); // The above doesn't seem to work for everyone (why?)
 
  sensors.begin(); //start up temp sensor
  sensors.requestTemperatures(); // Get the temperature
  tinytx.temp=(sensors.getTempCByIndex(0)*100); // Read first sensor and convert to integer, reversed at receiving end
  
  digitalWrite(ONE_WIRE_POWER, LOW); // turn DS18B20 off
  
  tinytx.supplyV = readVcc(); // Get supply voltage

  rfwrite(); // Send data via RF 

  Sleepy::loseSomeTime(60000); //JeeLabs power save function: enter low power mode for 60 seconds (valid range 16-65000 ms)

}

A question occurred to me while I was working on this. Does it still make sense to use JeeLib for the low-power sleep function when it is no longer used as the RFM library?

Hi @brandock , please have a look at avr/sleep.h this should make JeeLib.h for the low-power sleep function obsolete.Thanks for updating the TinyTX, I still have 14 TinyTX running, the 1.2V batteries (3 pieces AA) are already 7 years in operation and the system runs and runs…

I have three I use all the time, and a few others that I use when I need them.

Wow. I am running mine on 2 AA Eneloop batteries each. They last many months before recharging. But not years!

I have my doubts about that and am interested in learning more.

  1. You’ll find #include <avr/sleep.h> in jeelib/Ports.cpp, where Sleepy is defined. So it strikes me that Sleepy might give us more than avr/sleep.h by itself?
  2. I believe avr/sleep.h is older (circa 2002) than JeeLib Sleepy (circa 2009)?
  3. The latest emonTx firmware still uses Sleepy despite the switch to RFM69.