From 29aa3cda7aaa55713a7ce26af2ddf3fc7569f827 Mon Sep 17 00:00:00 2001 From: LowPowerLab Date: Thu, 23 Apr 2015 22:12:14 -0400 Subject: [PATCH] Add RFM69 SY310 pulse meter example --- Examples/DoorBellMote/DoorBellMote.ino | 1 + Examples/PulseMeter/PulseMeter.ino | 261 +++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 Examples/PulseMeter/PulseMeter.ino diff --git a/Examples/DoorBellMote/DoorBellMote.ino b/Examples/DoorBellMote/DoorBellMote.ino index 95a994b..2adea36 100644 --- a/Examples/DoorBellMote/DoorBellMote.ino +++ b/Examples/DoorBellMote/DoorBellMote.ino @@ -152,6 +152,7 @@ void loop() if (ring) { pulseRelay(); + radio.sendWithRetry(GATEWAYID, "RING OK", 4); ring = false; } diff --git a/Examples/PulseMeter/PulseMeter.ino b/Examples/PulseMeter/PulseMeter.ino new file mode 100644 index 0000000..335303d --- /dev/null +++ b/Examples/PulseMeter/PulseMeter.ino @@ -0,0 +1,261 @@ +// Sample RFM69 sketch for PulseMote - reading an EE-SY310 based water/pulse meter +// Example: https://lowpowerlab.com/blog/2013/02/02/meet-the-watermote-moteino-based-water-meter-reader-ee-sy310/ +// Copyright (c) 2015 Felix Rusu (felix@lowpowerlab.com). All rights reserved. +// ********************************************************************************** +// 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: http://github.com/lowpowerlab/rfm69 +#include //get it here: http://github.com/lowpowerlab/spiflash +#include //get it here: https://github.com/LowPowerLab/WirelessProgramming +#include +#include +#include +//********************************************************************************************* +//************ IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE ************* +//********************************************************************************************* +#define NODEID 5 +#define GATEWAYID 1 +#define NETWORKID 250 +#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ) +#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less! +//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! +#define PULSESPERGALLON 45 //how many pulses from sensor equal 1 gallon +#define GPMTHRESHOLD 8000 // GPM will reset after this many MS if no pulses are registered +#define XMITPERIOD 5000 // GPMthreshold should be less than 2*XMITPERIOD +//********************************************************************************************* +#ifdef __AVR_ATmega1284P__ + #define LED 15 // Moteino MEGAs have LEDs on D15 + #define INTERRUPTPIN 1 //INT1 = digital pin 11 (must be a hardware interrupt pin!) +#else + #define LED 9 // Moteinos have LEDs on D9 + #define INTERRUPTPIN 1 //INT1 = digital pin 3 (must be a hardware interrupt pin!) +#endif +//********************************************************************************************* +#define SERIAL_EN //uncomment this line to enable serial IO (when you debug Moteino and need serial output) +#define SERIAL_BAUD 115200 +#ifdef SERIAL_EN + #define DEBUG(input) {Serial.print(input);} + #define DEBUGln(input) {Serial.println(input);} +#else + #define DEBUG(input); + #define DEBUGln(input); +#endif + +RFM69 radio; +SPIFlash flash(8, 0xEF30); //WINDBOND 4MBIT flash chip on CS pin D8 (default for Moteino) + +volatile byte ledState = LOW; +volatile unsigned long PulseCounterVolatile = 0; // use volatile for shared variables +unsigned long NOW = 0; +unsigned long PulseCounter = 0; +unsigned long LASTMINUTEMARK = 0; +unsigned long PULSECOUNTLASTMINUTEMARK = 0; //keeps pulse count at the last minute mark + +byte COUNTEREEPROMSLOTS = 10; +unsigned long COUNTERADDRBASE = 8; //address in EEPROM that points to the first possible slot for a counter +unsigned long COUNTERADDR = 0; //address in EEPROM that points to the latest Counter in EEPROM +byte secondCounter = 0; + +unsigned long TIMESTAMP_pulse_prev = 0; +unsigned long TIMESTAMP_pulse_curr = 0; +int pulseAVGInterval = 0; +int pulsesPerXMITperiod = 0; +float GPM=0, GLM=0, GAL=0, GALlast=0, GPMlast=0, GLMlast=0; +byte sendLen; +char buff[80]; +char* GALstr="99999999999999.99"; //longest expected GAL message +char* GPMstr="99999.99"; //longest expected GPM message +char* GLMstr="9999999.99"; //longest expected GLM message +boolean WPReady = false; + +void setup() { + #ifdef SERIAL_EN + Serial.begin(SERIAL_BAUD); + #endif + + radio.initialize(FREQUENCY,NODEID,NETWORKID); +#ifdef IS_RFM69HW + radio.setHighPower(); //uncomment only for RFM69HW! +#endif + radio.encrypt(ENCRYPTKEY); + pinMode(LED, OUTPUT); + + //initialize counter from EEPROM + unsigned long savedCounter = EEPROM_Read_Counter(); + if (savedCounter <=0) savedCounter = 1; //avoid division by 0 + PulseCounterVolatile = PulseCounter = PULSECOUNTLASTMINUTEMARK = savedCounter; + attachInterrupt(INTERRUPTPIN, pulseCounterInterrupt, RISING); + Timer1.initialize(XMITPERIOD * 1000L); + Timer1.attachInterrupt(XMIT); + + sprintf(buff, "\nTransmitting at %d Mhz, id:%d nid:%d gid:%d", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915, NODEID, NETWORKID, GATEWAYID); + DEBUG(buff); + for (byte i=0;i GPMTHRESHOLD) + //more than 'GPMthreshold' seconds passed since last pulse... resetting GPM + pulsesPerXMITperiod=pulseAVGInterval=0; + else + { + pulsesPerXMITperiod++; + pulseAVGInterval += TIMESTAMP_pulse_curr - TIMESTAMP_pulse_prev; + } + interrupts(); +} + +void XMIT() +{ + noInterrupts(); + PulseCounter = PulseCounterVolatile; + interrupts(); + + if (millis() - TIMESTAMP_pulse_curr >= 5000) + { + ledState = !ledState; + digitalWrite(LED, ledState); + } + + //calculate Gallons counter + GAL = ((float)PulseCounter)/PULSESPERGALLON; + DEBUG("PulseCounter:");DEBUG(PulseCounter);DEBUG(", GAL: "); DEBUGln(GAL); + + //calculate & output GPM + GPM = pulseAVGInterval > 0 ? 60.0 * 1000 * (1.0/PULSESPERGALLON)/(pulseAVGInterval/pulsesPerXMITperiod) + : 0; + dtostrf(GAL,3,2, GALstr); + dtostrf(GPM,3,2, GPMstr); + + pulsesPerXMITperiod = 0; + pulseAVGInterval = 0; + secondCounter += XMITPERIOD/1000; + + //once per minute, output a GallonsLastMinute count + if (secondCounter>=60) + { + //DEBUG("60sec mark ... "); + secondCounter=0; + GLM = ((float)(PulseCounter - PULSECOUNTLASTMINUTEMARK))/PULSESPERGALLON; + PULSECOUNTLASTMINUTEMARK = PulseCounter; + EEPROM_Write_Counter(PulseCounter); + dtostrf(GLM,3,2, GLMstr); + sprintf(buff, "GAL:%s GPM:%s GLM:%s", GALstr, GPMstr, GLMstr); + //DEBUGln("done"); + } + else + { + sprintf(buff, "GAL:%s GPM:%s", GALstr, GPMstr); + } + + if (GPM!=GPMlast || GAL!=GALlast || GLM!=GLMlast) + { + sendLen = strlen(buff); + radio.sendWithRetry(GATEWAYID, buff, sendLen); + GALlast = GAL; + GPMlast = GPM; + GLMlast = GLM; + } + + DEBUGln(buff); +} + +unsigned long EEPROM_Read_Counter() +{ + return EEPROM_Read_ULong(EEPROM_Read_ULong(COUNTERADDR)); +} + +void EEPROM_Write_Counter(unsigned long counterNow) +{ + if (counterNow == EEPROM_Read_Counter()) + { + DEBUG("{EEPROM-SKIP(no changes)}"); + return; //skip if nothing changed + } + + DEBUG("{EEPROM-SAVE("); + DEBUG(EEPROM_Read_ULong(COUNTERADDR)); + DEBUG(")="); + DEBUG(PulseCounter); + DEBUG("}"); + + unsigned long CounterAddr = EEPROM_Read_ULong(COUNTERADDR); + if (CounterAddr == COUNTERADDRBASE+8*(COUNTEREEPROMSLOTS-1)) + CounterAddr = COUNTERADDRBASE; + else CounterAddr += 8; + + EEPROM_Write_ULong(CounterAddr, counterNow); + EEPROM_Write_ULong(COUNTERADDR, CounterAddr); +} + +unsigned long EEPROM_Read_ULong(int address) +{ + unsigned long temp; + for (byte i=0; i<8; i++) + temp = (temp << 8) + EEPROM.read(address++); + return temp; +} + +void EEPROM_Write_ULong(int address, unsigned long data) +{ + for (byte i=0; i<8; i++) + { + EEPROM.write(address+7-i, data); + data = data >> 8; + } +}