diff --git a/Examples/MailboxNotifier/MailboxNotifier4_sender.ino b/Examples/MailboxNotifier/MailboxNotifier4_sender.ino index f54ecad..bbe25db 100644 --- a/Examples/MailboxNotifier/MailboxNotifier4_sender.ino +++ b/Examples/MailboxNotifier/MailboxNotifier4_sender.ino @@ -1,11 +1,14 @@ -// Sample RFM69 sender/node sketch for motion sensor +// Sample RFM69 sender/node sketch for mailbox motion sensor // http://www.lowpowerlab.com/mailbox // 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 +// It then wakes up every 32 seconds and sends a message indicating when the last +// motion event happened (days, hours, minutes, seconds ago) and the battery level // In sleep mode, Moteino + PIR motion sensor use about ~78uA +// Make sure you adjust the settings in the configuration section below !!! // ********************************************************************************** -// Copyright LowPowerLab.com +// Copyright Felix Rusu, LowPowerLab.com // Library and code by Felix Rusu - felix@lowpowerlab.com // Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ // ********************************************************************************** @@ -14,22 +17,21 @@ // 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 2 of the License, or +// 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 +// 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, write -// to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// Public License along with this program. +// If not, see . // // Licence can be viewed at -// http://www.fsf.org/licenses/gpl.txt +// 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 @@ -40,27 +42,28 @@ #include //get library from: https://github.com/LowPowerLab/LowPower //writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/ +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* #define NODEID 55 //unique for each node on same network #define NETWORKID 250 //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 IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! - #define FREQUENCY RF69_915MHZ +#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! #define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +#define SENDEVERYXLOOPS 4 //each loop sleeps 8 seconds, so send status message every this many loops (default "4" = 32 seconds) +//********************************************************************************************* #define MOTIONPIN 1 //hardware interrupt 1 (D3) #define BATTERYSENSE A7 //through 1Meg+470Kohm and 0.1uF cap from battery VCC - this ratio divides the voltage to bring it below 3.3V where it is scaled to a readable range #define LED 9 // Moteinos have LEDs on D9 -//#define BLINK_EN //uncomment to make LED flash when messages are sent - -#define SENDEVERYXLOOPS 4 //each loop sleeps 8 seconds, so send status message every this many loops +//#define BLINK_EN //uncomment to make LED flash when messages are sent, leave out if you want low power #define SERIAL_BAUD 115200 -//#define SERIAL_EN //uncomment this line to enable serial IO debug messages +//#define SERIAL_EN //uncomment this line to enable serial IO debug messages, leave out if you want low power #ifdef SERIAL_EN #define DEBUG(input) {Serial.print(input); delay(1);} #define DEBUGln(input) {Serial.println(input); delay(1);} @@ -69,7 +72,6 @@ #define DEBUGln(input); #endif -int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms) RFM69 radio; volatile boolean motionDetected=false; @@ -171,4 +173,4 @@ void Blink(byte PIN, int DELAY_MS) digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); -} +} \ No newline at end of file diff --git a/Examples/MotionMote/MotionMote.ino b/Examples/MotionMote/MotionMote.ino index 41510fb..d6df047 100644 --- a/Examples/MotionMote/MotionMote.ino +++ b/Examples/MotionMote/MotionMote.ino @@ -1,15 +1,49 @@ -// Sample RFM69 sender/node sketch for motion sensor +// Sample RFM69 sender/node sketch for the MotionMote +// http://lowpowerlab.com/motion // 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 -// Library and code by Felix Rusu - felix@lowpowerlab.com // Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ +// Make sure you adjust the settings in the configuration section below !!! + +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// 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 . +// +// 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 +// ********************************************************************************** #include //get it here: https://www.github.com/lowpowerlab/rfm69 -#include //get it here: https://github.com/lowpowerlab/spiflash -#include //get library from: https://github.com/LowPowerLab/LowPower +#include +#include //get library from: https://github.com/lowpowerlab/lowpower + //writeup here: http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/ -#define NODEID 18 //unique for each node on same network +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NODEID 88 //unique for each node on same network #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): @@ -17,14 +51,31 @@ //#define FREQUENCY RF69_868MHZ #define FREQUENCY RF69_915MHZ #define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! -//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W! +//********************************************************************************************* + #define ACK_TIME 30 // max # of ms to wait for an ack -#define LED 9 // Moteinos have LEDs on D9 -#define SERIAL_BAUD 115200 +#define ONBOARDLED 9 // Moteinos have LEDs on D9 +#define EXTLED 5 // MotionOLEDMote has an external LED on D5 +#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 ~= 880 (ratio given by 10k+4.7K divider from VBAT_COND = 1.47 multiplier) #define MOTIONPIN 1 //hardware interrupt 1 (D3) +//#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 + RFM69 radio; volatile boolean motionDetected=false; +float batteryVolts = 5; +char* BATstr="BAT:5.00v"; +char sendBuf[32]; +byte sendLen; void setup() { Serial.begin(SERIAL_BAUD); @@ -33,10 +84,13 @@ void setup() { radio.setHighPower(); //uncomment only for RFM69HW! #endif radio.encrypt(ENCRYPTKEY); + pinMode(MOTIONPIN, INPUT); attachInterrupt(MOTIONPIN, motionIRQ, RISING); char buff[50]; sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); - Serial.println(buff); + DEBUGln(buff); + pinMode(ONBOARDLED, OUTPUT); + pinMode(EXTLED, OUTPUT); } void motionIRQ() @@ -47,15 +101,30 @@ void motionIRQ() void loop() { if (motionDetected) { - if (radio.sendWithRetry(GATEWAYID, "MOTION", 6)) + digitalWrite(EXTLED, HIGH); + //TODO: read several samples and take average + //TODO: read analog only every N cycles + batteryVolts = analogRead(A7) * 0.00322 * 1.42; + dtostrf(batteryVolts, 3,2, BATstr); + //sprintf(sendBuf, "MOTION ............................................ BAT:%sv", BATstr); + sprintf(sendBuf, "MOTION BAT:%sv", BATstr); + sendLen = strlen(sendBuf); + + if (radio.sendWithRetry(GATEWAYID, sendBuf, sendLen)) { - Serial.println(" ok!"); - Blink(LED,3); + DEBUG("MOTION ACK:OK! RSSI:"); + DEBUG(radio.RSSI); } - else Serial.println(" nothing..."); + else DEBUG("MOTION ACK:NOK..."); + + DEBUG(" VIN: "); + DEBUGln(BATstr); + + radio.sleep(); + //Blink(EXTLED,50); //Blink(ONBOARDLED,3); motionDetected=false; + digitalWrite(EXTLED, LOW); } - radio.sleep(); LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); } @@ -65,4 +134,4 @@ void Blink(byte PIN, int DELAY_MS) digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); -} +} \ No newline at end of file diff --git a/Examples/MotionMote/OLD/MotionMote.ino b/Examples/MotionMote/OLD/MotionMote.ino new file mode 100644 index 0000000..41510fb --- /dev/null +++ b/Examples/MotionMote/OLD/MotionMote.ino @@ -0,0 +1,68 @@ +// Sample RFM69 sender/node sketch for motion sensor +// 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 +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get the RFM69 and SPIFlash library at: https://github.com/LowPowerLab/ + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include //get it here: https://github.com/lowpowerlab/spiflash +#include //get library from: https://github.com/LowPowerLab/LowPower + +#define NODEID 18 //unique for each node on same network +#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 +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define ACK_TIME 30 // max # of ms to wait for an ack +#define LED 9 // Moteinos have LEDs on D9 +#define SERIAL_BAUD 115200 +#define MOTIONPIN 1 //hardware interrupt 1 (D3) + +RFM69 radio; +volatile boolean motionDetected=false; + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + attachInterrupt(MOTIONPIN, motionIRQ, RISING); + char buff[50]; + sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); +} + +void motionIRQ() +{ + motionDetected=true; +} + +void loop() { + if (motionDetected) + { + if (radio.sendWithRetry(GATEWAYID, "MOTION", 6)) + { + Serial.println(" ok!"); + Blink(LED,3); + } + else Serial.println(" nothing..."); + motionDetected=false; + } + radio.sleep(); + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} diff --git a/Examples/MotionMote/MotionMote.jpg b/Examples/MotionMote/OLD/MotionMote.jpg similarity index 100% rename from Examples/MotionMote/MotionMote.jpg rename to Examples/MotionMote/OLD/MotionMote.jpg diff --git a/Examples/MotionMote/MotionMote_CC-BY-SA.svg b/Examples/MotionMote/OLD/MotionMote_CC-BY-SA.svg similarity index 100% rename from Examples/MotionMote/MotionMote_CC-BY-SA.svg rename to Examples/MotionMote/OLD/MotionMote_CC-BY-SA.svg diff --git a/Examples/OLEDMote/OLEDMote.ino b/Examples/OLEDMote/OLEDMote.ino new file mode 100644 index 0000000..0204aa5 --- /dev/null +++ b/Examples/OLEDMote/OLEDMote.ino @@ -0,0 +1,241 @@ +// Sample RFM69 sketch for the MotionOLED mote containing the OLED +// Passes through any wireless received messages to the serial port & responds to ACKs +// Library and code by Felix Rusu - felix@lowpowerlab.com +// Get libraries at: https://github.com/LowPowerLab/ +// Make sure you adjust the settings in the configuration section below !!! + +// ********************************************************************************** +// Copyright Felix Rusu, LowPowerLab.com +// Library and code by Felix Rusu - felix@lowpowerlab.com +// ********************************************************************************** +// 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 . +// +// 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 +// ********************************************************************************** + +#include //get it here: https://www.github.com/lowpowerlab/rfm69 +#include +#include //get library from: https://github.com/lowpowerlab/lowpower +#include "U8glib.h" //get library from: https://code.google.com/p/u8glib/ + +//********************************************************************************************* +// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NODEID 122 //unique for each node on same network +#define NETWORKID 100 //the same on all nodes that talk to each other +//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 +#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! +#define IS_RFM69HW //uncomment only for RFM69HW! Remove/comment if you have RFM69W! +//********************************************************************************************* + +#define SERIAL_BAUD 115200 +#define LED 5 // Moteinos have LEDs on D9, but for MotionMote we are using the external led on D5 +#define BUZZER 6 +#define BUTTON_INT 1 //user button on interrupt 1 +#define BUTTON_PIN 3 //user button on interrupt 1 + +RFM69 radio; +U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // I2C / TWI SSD1306 OLED 128x64 +bool promiscuousMode = true; //set to 'true' to sniff all packets on the same network + +void setup() { + Serial.begin(SERIAL_BAUD); + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + radio.promiscuous(promiscuousMode); + char buff[50]; + sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); + Serial.println(buff); + pinMode(BUZZER, OUTPUT); + + //configure OLED + u8g.setRot180(); //flip screen + // assign default color value + if ( u8g.getMode() == U8G_MODE_R3G3B2 ) + u8g.setColorIndex(255); // white + else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) + u8g.setColorIndex(3); // max intensity + else if ( u8g.getMode() == U8G_MODE_BW ) + u8g.setColorIndex(1); // pixel on + else if ( u8g.getMode() == U8G_MODE_HICOLOR ) + u8g.setHiColorByRGB(255,255,255); + u8g.begin(); + Serial.flush(); + pinMode(BUTTON_PIN, INPUT_PULLUP); + attachInterrupt(BUTTON_INT, handleButton, FALLING); +} + +#define FLAG_INTERRUPT 0x01 +volatile int mainEventFlags = 0; +boolean buttonPressed = false; +void handleButton() +{ + mainEventFlags |= FLAG_INTERRUPT; +} + +byte ackCount=0; + +#define MSG_MAX_LEN 17 //OLED 1 line max # of chars (16 + EOL) +#define HISTORY_LEN 10 //hold this many past messages +typedef struct { + char data[MSG_MAX_LEN]; + int rssi; + byte from; +} Message; +Message * messageHistory = new Message[HISTORY_LEN]; + +byte lastMessageIndex = HISTORY_LEN; +byte currMessageIndex = HISTORY_LEN; +byte historyLength = 0; +void loop() { + if (mainEventFlags & FLAG_INTERRUPT) + { + LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_ON); + mainEventFlags &= ~FLAG_INTERRUPT; + if (!digitalRead(BUTTON_PIN)) { + buttonPressed=true; + } + } + + if (buttonPressed) + { + buttonPressed = false; + Beep(10, false); + + //save non-ACK messages in a circular buffer + if (!radio.ACK_RECEIVED && historyLength > 1) //only care if at least 2 messages saved. if only 1 message it should be displayed already + { + if (currMessageIndex==0) + currMessageIndex=historyLength-1; + else currMessageIndex--; + + //Serial.print("HIST currIndex/histLen=");Serial.print(currMessageIndex+1);Serial.print("/");Serial.print(historyLength); + //Serial.print(" - "); + //Serial.println(messageHistory[currMessageIndex].data); + + u8g.firstPage(); + do { + draw(messageHistory[currMessageIndex].data, messageHistory[currMessageIndex].rssi, messageHistory[currMessageIndex].from, true); + } while(u8g.nextPage()); + //delay(10); //give OLED time to draw? + } + } + + if (radio.receiveDone()) + { + Serial.print('[');Serial.print(radio.SENDERID);Serial.print("] "); + if (promiscuousMode) + Serial.print("to [");Serial.print(radio.TARGETID);Serial.print("] "); + + Serial.print((char*)radio.DATA); + Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]"); + Serial.println(); + + saveToHistory((char *)radio.DATA, radio.RSSI, radio.SENDERID); + Blink(LED,3); + Beep(20, true); + u8g.firstPage(); + do { + draw((char*)radio.DATA, radio.RSSI, radio.SENDERID, false); + } while(u8g.nextPage()); + //delay(10); //give OLED time to draw? + } + radio.receiveDone(); + Serial.flush(); + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON); +} + +float batteryVolts = 5; +char* BATstr="BAT:5.00v"; +void draw(char * data, int rssi, byte from, boolean isHist) { + char buff[20]; + // graphic commands to redraw the complete screen should be placed here + u8g.setFont(u8g_font_unifont); + u8g.drawStr( 0, 10, data); + sprintf(buff, "ID:%d", from); + u8g.drawStr( 0, 25, buff); + sprintf(buff, "RSSI:%d", rssi); + u8g.drawStr( 60, 25, buff); + + if (!isHist) + { + batteryVolts = analogRead(A7) * 0.00322 * 1.42; + dtostrf(batteryVolts, 3,2, BATstr); + sprintf(buff, "BAT:%sv", BATstr); + u8g.drawStr( 0, 55, buff); + } +} + +void Beep(byte theDelay, boolean both) +{ + if (theDelay > 20) theDelay = 20; + tone(BUZZER, 4200); //4200 + delay(theDelay); + noTone(BUZZER); + LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_ON); + if (both) + { + tone(BUZZER, 4500); //4500 + delay(theDelay); + noTone(BUZZER); + } +} + +void Blink(byte PIN, int DELAY_MS) +{ + pinMode(PIN, OUTPUT); + digitalWrite(PIN,HIGH); + delay(DELAY_MS); + digitalWrite(PIN,LOW); +} + +void saveToHistory(char * msg, int rssi, byte from) +{ + byte length = strlen(msg); + byte i = 0; + if (lastMessageIndex >=9) lastMessageIndex = 0; + else lastMessageIndex++; + currMessageIndex = lastMessageIndex; + if (historyLength < HISTORY_LEN) historyLength++; + + //Serial.print("HIST SAVE lastIndex=");Serial.print(lastMessageIndex);Serial.print(" strlen=");Serial.print(length); + //Serial.print(" msg=["); + + for (; i<(MSG_MAX_LEN-1) && (i < length); i++) + { + messageHistory[lastMessageIndex].data[i] = msg[i]; + Serial.print(msg[i]); + } + //Serial.print("] copied:"); + messageHistory[lastMessageIndex].data[i] = '\0'; //terminate string + //Serial.println((char*)messageHistory[lastMessageIndex].data); + + messageHistory[lastMessageIndex].rssi = rssi; + messageHistory[lastMessageIndex].from = from; +} \ No newline at end of file