Low Power Means Putting Things to Sleep!
 Plugged in a new XBee on the FTDI cable and couldn't remember the right terminal settings (9600, Raw, Echo,  then +++ with no return should get an OK.) I used ATID2711, ATMY0, ATDL1, ATBD6 to match the one at the sailboat end of the IOM controller so the TX can listen to either one at 57600 baud. Don't forget the ATWR to write it all out! Upgraded the IOM TX program to echo any serial it gets back on the XBee to the console.
Plugged in a new XBee on the FTDI cable and couldn't remember the right terminal settings (9600, Raw, Echo,  then +++ with no return should get an OK.) I used ATID2711, ATMY0, ATDL1, ATBD6 to match the one at the sailboat end of the IOM controller so the TX can listen to either one at 57600 baud. Don't forget the ATWR to write it all out! Upgraded the IOM TX program to echo any serial it gets back on the XBee to the console.Now to get a trinket talking to the XBee... I couldn't get software serial to work reliably on the trinket at 57600, so backed all the XBees down to 19200. I created SleepyTrinket based on the code from Nathan Seidle at https://github.com/sparkfun/H2OhNo/tree/master/firmware/WatchDogTest. That code uses pins 3 and 4 for the software serial, but I switched it to 0 and 1, then used pin 2 for the XBee sleep line, which leaves 3 (A3) and 4 (A2) for something analog useful. I cut the current draw on the trinket by 3 mA by breaking off the green power LED. The XBee sleeps when pin 9 is set high if sleep mode is enabled (ATSM1 for hibernate or ATSM2 for doze, plus ATWR).
 I first powered the Trinket and the XBee directly on the 3V line from a 3.7 V 100 mAh LiPo, hoping to bypass any regulator losse, but that worried me a little so I switched to the regulated battery input. Either way, with everything awake it used about 60 mA and with everything asleep that fell to about 40 uA! That's about 1 mAh per day while sleeping and 1 mAh per minute while awake.
I first powered the Trinket and the XBee directly on the 3V line from a 3.7 V 100 mAh LiPo, hoping to bypass any regulator losse, but that worried me a little so I switched to the regulated battery input. Either way, with everything awake it used about 60 mA and with everything asleep that fell to about 40 uA! That's about 1 mAh per day while sleeping and 1 mAh per minute while awake.How quickly can I wake everything up, spit out a serial burst and go back to sleep? It works with delays in the code of 1 s, 500 ms, 100 ms, so 50 ms is probably fast enough with a total time around 200 ms per burst. To split the power consumption between awake and asleep would mean reporting about 300 times a day or about once every 5 seconds.
When I enabled the ADC and started reading a TMP 36 the sleep load came up to about 270 uA, or about 6 mAh per day, which would still get months on a 1300 mAh battery. Still, enabling and disabling the ADC each cycle brings the sleep load back down to about 60 uA. Better stability for the TMP 36 comes from a 2 M resistor and a 104 ceramic cap bridging the signal pin to ground. Based on these measurements, the little 500 mAh LiPo in the background should be good for more than 6 months between recharges. The next step is a little tidier packaging and something at the house end that will listen, repeat the data out to the world, and maybe send an SMS if alarm conditions come up.
A little more testing shows that the accuracy of the temperature measurements from this combo are a little dodgy, so time to track down where the error comes from. (Yes I know that the TMP36 spec says +-2C, but I want better ;-) )
/*
Use with Adafruit Trinket 3V - remove green power LED - compile as trinket 8MHz
about 6 mA awake and 25 uA asleep, 10 mA if the LED is turned on for just the trinket
sleep current goes up to about 1 mA if connected to FTDI cable
2014-02-11
Rick Sellens adapted from:
1-14-2013
Spark Fun Electronics
Nathan Seidle
This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
https://github.com/sparkfun/H2OhNo/tree/master/firmware/WatchDogTest
*/
#define TRX 1 // Trinket RX pin
#define TTX 0 // Trinket TX pin
#define XBS 2 // XBee sleep pin
#define BLNK 1 // Blinking LED pin
#define TMP 2 // Analog pin number for TMP 36
#define WT 50
#include <avr/sleep.h> //Needed for sleep_mode
#include <SoftwareSerial.h>
SoftwareSerial mySerial(1, 0); // RX, TX
volatile int watchdog_counter;
//This runs each time the watch dog wakes us up from sleep
ISR(WDT_vect) {
watchdog_counter++;
}
void setup()
{
digitalWrite(XBS,LOW); // start with the XBee awake
delay(WT);
mySerial.begin(19200); // flaky at 57600, but seems OK at 9600, 19200, 38400
delay(WT);
mySerial.println("\n\nRWS Sleeper");
pinMode(XBS,OUTPUT);
pinMode(BLNK,OUTPUT);
delay(WT);
watchdog_counter = 0;
//Power down various bits of hardware to lower power usage
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Power down everything, wake up from WDT
sleep_enable();
ADCSRA |= (1<<ADEN); //Enable ADC, costs ~230uA
ADCSRA &= ~(1<<ADEN); //Disable ADC, saves ~230uA
setup_watchdog(6); //Wake up after 1 sec (6)
}
void loop() {
static int rdg = 0;
static int n = 0;
digitalWrite(XBS,HIGH); // sleep the XBee
sleep_mode(); // sleep the trinket
if(watchdog_counter > 0){
// trinket awake, so take a reading
ADCSRA |= (1<<ADEN); //Enable ADC, costs ~230uA
delay(WT);
rdg += analogRead(TMP);
n++;
ADCSRA &= ~(1<<ADEN); //Disable ADC, saves ~230uA
if(watchdog_counter > 9){ // wake the XBee every 10 counts
digitalWrite(BLNK,HIGH); // LED on
digitalWrite(XBS,LOW); // wake the XBee
delay(WT);
mySerial.print("Awakened... ");
delay(WT);
digitalWrite(BLNK,LOW); // LED off
long int itemp = rdg; // temperature in tenths of a degree C
itemp = (itemp * 3300 / 1024) / n - 500;
mySerial.print(itemp);
mySerial.println(" tenths of a degree C. ZZZ...");
delay(WT);
// rest the accumulator and counters
watchdog_counter = 0;
rdg = 0;
n = 0;
}
}
}
// 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
// 6=1sec, 7=2sec, 8=4sec, 9=8sec
// From: http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void setup_watchdog(int timerPrescaler) {
if (timerPrescaler > 9 ) timerPrescaler = 9; //Correct incoming amount if need be
byte bb = timerPrescaler & 7;
if (timerPrescaler > 7) bb |= (1<<5); //Set the special 5th bit if necessary
//This order of commands is important and cannot be combined
MCUSR &= ~(1<<WDRF); //Clear the watch dog reset
WDTCR |= (1<<WDCE) | (1<<WDE); //Set WD_change enable, set WD enable
WDTCR = bb; //Set new watchdog timeout value
WDTCR |= _BV(WDIE); //Set the interrupt enable, this will keep unit from resetting after each int
}

