2014-10-17 17:32:03 +01:00
// Sample RFM69 sender/node sketch for the MotionMote
// http://lowpowerlab.com/motion
2013-11-10 05:26:34 +00:00
// PIR motion sensor connected to D3 (INT1)
// When RISE happens on D3, the sketch transmits a "MOTION" msg to receiver Moteino and goes back to sleep
// In sleep mode, Moteino + PIR motion sensor use about ~78uA
// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/
2014-10-17 17:32:03 +01:00
// Make sure you adjust the settings in the configuration section below !!!
// **********************************************************************************
2015-11-11 03:57:38 +00:00
// Copyright Felix Rusu of LowPowerLab.com, 2015-11-10
// RFM69 library and sample code by Felix Rusu - lowpowerlab.com/contact
2014-10-17 17:32:03 +01:00
// **********************************************************************************
// License
// **********************************************************************************
// This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU General
// Public License as published by the Free Software
// Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General
// Public License along with this program.
// If not, see <http://www.gnu.org/licenses/>.
//
// Licence can be viewed at
// http://www.gnu.org/licenses/gpl-3.0.txt
//
// Please maintain this license information along with authorship
// and copyright notices in any redistribution of this code
// **********************************************************************************
2014-03-05 13:53:15 +00:00
# include <RFM69.h> //get it here: https://www.github.com/lowpowerlab/rfm69
2015-11-11 03:57:38 +00:00
# include <RFM69_ATC.h>//get it here: https://www.github.com/lowpowerlab/rfm69
# include <SPI.h> //comes with Arduino IDE (www.arduino.cc)
2014-10-17 17:32:03 +01:00
# include <LowPower.h> //get library from: https://github.com/lowpowerlab/lowpower
//writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
2013-11-10 05:26:34 +00:00
2014-10-17 17:32:03 +01:00
//*********************************************************************************************
2015-11-11 03:57:38 +00:00
//************ IMPORTANT SETTINGS - YOU MUST CHANGE/CONFIGURE TO FIT YOUR HARDWARE *************
2014-10-17 17:32:03 +01:00
//*********************************************************************************************
# define NODEID 88 //unique for each node on same network
2013-11-10 05:26:34 +00:00
# define NETWORKID 100 //the same on all nodes that talk to each other
# define GATEWAYID 1
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
//#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
# define FREQUENCY RF69_915MHZ
2016-04-13 14:52:44 +01:00
# define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W!
2015-11-11 03:57:38 +00:00
# define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
# define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL
2016-04-13 14:52:44 +01:00
# define ATC_RSSI -75
2014-10-17 17:32:03 +01:00
//*********************************************************************************************
2015-11-11 03:57:38 +00:00
# define ACK_TIME 30 // max # of ms to wait for an ack
2014-10-17 17:32:03 +01:00
# define ONBOARDLED 9 // Moteinos have LEDs on D9
2015-11-11 03:57:38 +00:00
# define LED 5 // MotionOLEDMote has an external LED on D5
# define MOTION_PIN 3 // D3
# define MOTION_IRQ 1 // hardware interrupt 1 (D3) - where motion sensors OUTput is connected, this will generate an interrupt every time there is MOTION
# define BATT_MONITOR A7 // Sense VBAT_COND signal (when powered externally should read ~3.25v/3.3v (1000-1023), when external power is cutoff it should start reading around 2.85v/3.3v * 1023 ~= 883 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier)
# define BATT_CYCLES 450 // read and report battery voltage every this many sleep cycles (ex 30cycles * 8sec sleep = 240sec/4min). For 450 cyclesyou would get ~1 hour intervals
2016-04-13 14:52:44 +01:00
# define BATT_FORMULA(reading) reading * 0.00322 * 1.49 // >>> fine tune this parameter to match your voltage when fully charged
2015-11-11 03:57:38 +00:00
// details on how this works: https://lowpowerlab.com/forum/index.php/topic,1206.0.html
2014-10-17 17:32:03 +01:00
//#define SERIAL_EN //comment this out when deploying to an installed SM to save a few KB of sketch size
# define SERIAL_BAUD 115200
# ifdef SERIAL_EN
# define DEBUG(input) {Serial.print(input); delay(1);}
# define DEBUGln(input) {Serial.println(input); delay(1);}
# else
# define DEBUG(input);
# define DEBUGln(input);
# endif
2015-11-11 03:57:38 +00:00
# ifdef ENABLE_ATC
RFM69_ATC radio ;
# else
RFM69 radio ;
# endif
2013-11-10 05:26:34 +00:00
volatile boolean motionDetected = false ;
2014-10-17 17:32:03 +01:00
float batteryVolts = 5 ;
2016-01-12 04:10:02 +00:00
char BATstr [ 10 ] ; //longest battery voltage reading message = 9chars
2014-10-17 17:32:03 +01:00
char sendBuf [ 32 ] ;
byte sendLen ;
2013-11-10 05:26:34 +00:00
2015-11-11 03:57:38 +00:00
void motionIRQ ( void ) ;
void checkBattery ( void ) ;
2013-11-10 05:26:34 +00:00
void setup ( ) {
Serial . begin ( SERIAL_BAUD ) ;
radio . initialize ( FREQUENCY , NODEID , NETWORKID ) ;
# ifdef IS_RFM69HW
radio . setHighPower ( ) ; //uncomment only for RFM69HW!
# endif
radio . encrypt ( ENCRYPTKEY ) ;
2015-11-11 03:57:38 +00:00
//Auto Transmission Control - dials down transmit power to save battery (-100 is the noise floor, -90 is still pretty good)
//For indoor nodes that are pretty static and at pretty stable temperatures (like a MotionMote) -90dBm is quite safe
//For more variable nodes that can expect to move or experience larger temp drifts a lower margin like -70 to -80 would probably be better
//Always test your ATC mote in the edge cases in your own environment to ensure ATC will perform as you expect
# ifdef ENABLE_ATC
2016-04-13 14:52:44 +01:00
radio . enableAutoPower ( ATC_RSSI ) ;
2015-11-11 03:57:38 +00:00
# endif
pinMode ( MOTION_PIN , INPUT ) ;
attachInterrupt ( MOTION_IRQ , motionIRQ , RISING ) ;
2013-11-10 05:26:34 +00:00
char buff [ 50 ] ;
sprintf ( buff , " \n Transmitting at %d Mhz... " , FREQUENCY = = RF69_433MHZ ? 433 : FREQUENCY = = RF69_868MHZ ? 868 : 915 ) ;
2014-10-17 17:32:03 +01:00
DEBUGln ( buff ) ;
pinMode ( ONBOARDLED , OUTPUT ) ;
2015-11-11 03:57:38 +00:00
pinMode ( LED , OUTPUT ) ;
radio . sendWithRetry ( GATEWAYID , " START " , 5 ) ;
# ifdef ENABLE_ATC
DEBUGln ( " RFM69_ATC Enabled (Auto Transmission Control) \n " ) ;
# endif
2013-11-10 05:26:34 +00:00
}
void motionIRQ ( )
{
motionDetected = true ;
2015-11-11 03:57:38 +00:00
DEBUGln ( " IRQ " ) ;
2013-11-10 05:26:34 +00:00
}
2015-11-11 13:48:18 +00:00
uint16_t batteryReportCycles = 0 ;
2013-11-10 05:26:34 +00:00
void loop ( ) {
2014-11-03 17:02:11 +00:00
checkBattery ( ) ;
2013-11-10 05:26:34 +00:00
if ( motionDetected )
{
2015-11-11 03:57:38 +00:00
digitalWrite ( LED , HIGH ) ;
2014-10-17 17:32:03 +01:00
sprintf ( sendBuf , " MOTION BAT:%sv " , BATstr ) ;
sendLen = strlen ( sendBuf ) ;
if ( radio . sendWithRetry ( GATEWAYID , sendBuf , sendLen ) )
2013-11-10 05:26:34 +00:00
{
2014-10-17 17:32:03 +01:00
DEBUG ( " MOTION ACK:OK! RSSI: " ) ;
DEBUG ( radio . RSSI ) ;
2014-11-03 17:02:11 +00:00
batteryReportCycles = 0 ;
2013-11-10 05:26:34 +00:00
}
2014-10-17 17:32:03 +01:00
else DEBUG ( " MOTION ACK:NOK... " ) ;
DEBUG ( " VIN: " ) ;
DEBUGln ( BATstr ) ;
radio . sleep ( ) ;
2015-11-11 03:57:38 +00:00
digitalWrite ( LED , LOW ) ;
2013-11-10 05:26:34 +00:00
}
2014-11-03 17:02:11 +00:00
else if ( batteryReportCycles = = BATT_CYCLES )
{
sprintf ( sendBuf , " BAT:%sv " , BATstr ) ;
sendLen = strlen ( sendBuf ) ;
2015-11-11 03:57:38 +00:00
radio . sendWithRetry ( GATEWAYID , sendBuf , sendLen ) ;
2014-11-03 17:02:11 +00:00
radio . sleep ( ) ;
batteryReportCycles = 0 ;
}
2014-11-07 16:07:36 +00:00
motionDetected = false ; //do NOT move this after the SLEEP line below or motion will never be detected
2013-11-10 05:26:34 +00:00
LowPower . powerDown ( SLEEP_8S , ADC_OFF , BOD_OFF ) ;
2014-11-03 17:02:11 +00:00
batteryReportCycles + + ;
2013-11-10 05:26:34 +00:00
}
2016-01-12 04:10:02 +00:00
uint16_t cycleCount = BATT_CYCLES ;
2014-11-03 17:02:11 +00:00
void checkBattery ( )
2013-11-10 05:26:34 +00:00
{
2014-11-03 17:02:11 +00:00
if ( cycleCount + + = = BATT_CYCLES ) //only read battery every BATT_CYCLES sleep cycles
{
unsigned int readings = 0 ;
for ( byte i = 0 ; i < 10 ; i + + ) //take 10 samples, and average
readings + = analogRead ( BATT_MONITOR ) ;
2015-11-11 03:57:38 +00:00
batteryVolts = BATT_FORMULA ( readings / 10.0 ) ;
2014-11-03 17:02:11 +00:00
dtostrf ( batteryVolts , 3 , 2 , BATstr ) ; //update the BATStr which gets sent every BATT_CYCLES or along with the MOTION message
cycleCount = 0 ;
}
2014-10-17 17:32:03 +01:00
}