Author Topic: LoRa "mesh" with Moteino (non Mega)  (Read 2457 times)

syrinxtech

  • Sr. Member
  • ****
  • Posts: 347
  • Country: us
    • Syrinx Technologies
LoRa "mesh" with Moteino (non Mega)
« on: April 01, 2018, 09:57:27 AM »
Does anyone have any experience getting the RF95 radios to work when using the RHMesh manager on a non-Mega Moteino?  The issue always seems to be a lack of memory.  I have been playing a lot lately with a LoRa test environment using two Moteino's with an RF95 radio communicating to a Particle Photon with a RF95 radio.  I started with RHDatagram and worked my way up to RHReliableDatagram without incident.  I was able to find a basic encryption module that worked, even though it's obviously not as strong as that built-in to the RFM69 radios.

Once I tried to move up to RHMesh, the problems began.  Without a Mega, the memory available started causing the dreaded compiler warnings and output starting showing jibberish.  I love the concept of the meshed networking, but I don't want to have to spend the extra $$ to put in a Mega in possibly dozens of nodes (not a real world need, but a capability I'm designing into the project.

If anyone has done this successfully with a non-Mega Moteino, I would love to hear how you configured everything.

i670

  • NewMember
  • *
  • Posts: 20
  • Country: au
Re: LoRa "mesh" with Moteino (non Mega)
« Reply #1 on: April 01, 2018, 06:01:50 PM »
I've modified MotionMote to use Lora and mesh.  Perhaps this is helpful.

dave

Code: [Select]
// Sample RFM69 sender/node sketch for the MotionMote
// http://lowpowerlab.com/motionmote
// 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 ~60uA
// IMPORTANT: adjust the settings in the configuration section below !!!

// **********************************************************************************
// Copyright Felix Rusu of LowPowerLab.com, 2016
// **********************************************************************************
// 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.
//
// 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 <RHMesh.h>
#include <RH_RF95.h>
#include <SPI.h>      //comes with Arduino IDE (www.arduino.cc)
#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/
#include <SPIFlash.h> //get it here: https://www.github.com/lowpowerlab/spiflash
#include <Wire.h>     //comes with Arduino

//****************************************************************************************************************
//**** IMPORTANT RADIO SETTINGS - YOU MUST CHANGE/CONFIGURE TO MATCH YOUR HARDWARE TRANSCEIVER CONFIGURATION! ****
//****************************************************************************************************************
#define CLIENT_ADDRESS 6      // our network address
#define SERVER_ADDRESS 4      // address of the lora internet gateway
#define FREQUENCY  434
#define RETRIES 5          // this needs to be very large to allow our partner to do other things

//*********************************************************************************************
#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_FORMULA(reading) reading * 3.22 * 1.49 // >>> fine tune this parameter to match your voltage when fully charged
//#define BATT_FORMULA(reading) reading * 0.00322 * 1.49 // >>> fine tune this parameter to match your voltage when fully charged
// details on how this works: https://lowpowerlab.com/forum/index.php/topic,1206.0.html
#define DUPLICATE_INTERVAL 60000 //avoid duplicates in 55second intervals (ie mailman sometimes spends 30+ seconds at mailbox)
#define BATT_INTERVAL  14400000  // 4 hours; read and report battery voltage every this many ms (approx)

//#define SERIAL_EN             //comment this out when deploying to an installed Mote 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);}
#define DEBUGFlush() { Serial.flush(); }
#else
#define DEBUG(input);
#define DEBUGln(input);
#define DEBUGFlush();
#endif

#define FLASH_SS      8 // and FLASH SS on D8 on regular Moteinos (D23 on MoteinoMEGA)
SPIFlash flash(FLASH_SS, 0xEF30); //EF30 for 4mbit  Windbond chip (W25X40CL)

volatile boolean motionDetected = false;
float batteryVolts = 5;

uint32_t lastSleepTime = 0;

uint8_t buf[16];     // Note this should not need to be hard coded but referencing RH_MESH_MAX_MESSAGE_LEN doesn't seem to work; gets bad rc from sendtowait
uint8_t testMode = 0;
/*
   Structure of event record
*/
struct eventRec {
  uint8_t  reqType;
  uint8_t  motionStatus;
  uint16_t mv;
};
eventRec event;

void motionIRQ(void);
void checkBattery(void);

// Singleton instance of the radio driver
RH_RF95 driver;

// Class to manage message delivery and receipt, using the driver declared above
//RHReliableDatagram manager(driver, CLIENT_ADDRESS);    // this address is a lora client of the gateway
RHMesh manager(driver, CLIENT_ADDRESS);    // this address is a lora client of the gateway

void setup() {
  Serial.begin(SERIAL_BAUD);
  Serial.println(__FILE__);
  pinMode(MOTION_PIN, INPUT);
  attachInterrupt(MOTION_IRQ, motionIRQ, RISING);

  if (!manager.init()) {
    Serial.println(F("init failed"));
  }

  // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36
  driver.setModemConfig(RH_RF95::Bw125Cr45Sf128);
  driver.setFrequency(FREQUENCY);
  driver.setTxPower(23);
  driver.sleep();
  manager.setRetries(RETRIES);

  pinMode(LED, OUTPUT);
  event.reqType = 'M';
  if (flash.initialize()) flash.sleep(); //if Moteino has FLASH-MEM, make sure it sleeps
  checkBattery();
  sendEvent();
}

void motionIRQ()
{
  motionDetected = true;
  DEBUGln("IRQ");
}

uint16_t batteryReportCycles = 0;
uint32_t time = 0, now = 0, MLO = 0, BLO = 0;
byte motionRecentlyCycles = 0;

void loop() {
  now = millis();
  checkBattery();
  //DEBUG("Slept: ");DEBUG(now-lastSleepTime);DEBUGln("ms");

  if (motionDetected && (time - MLO > DUPLICATE_INTERVAL))
  {
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    MLO = time; //save timestamp of event
    event.motionStatus = 1;
    sendEvent();
    event.motionStatus = 0;
  }
  else if (time - BLO > BATT_INTERVAL)
  {
    DEBUGln("Battery update");
    BLO = time;
    batteryReportCycles = 0;
    sendEvent();
  }

  DEBUGFlush();

  //while motion recently happened sleep for small slots of time to better approximate last motion event
  //this helps with debouncing a "MOTION" event more accurately for sensors that fire the IRQ very rapidly (ie panasonic sensors)
  if (motionDetected || motionRecentlyCycles > 0)
  {
    if (motionDetected) motionRecentlyCycles = 8;
    else motionRecentlyCycles--;
    motionDetected = false; //do NOT move this after the SLEEP line below or motion will never be detected
    time = time + 250 + millis() - now;
    LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF);
    DEBUGln("WAKEUP250ms");
  }
  else
  {
    time = time + 8000 + millis() - now;
    lastSleepTime = millis();
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    DEBUGln("WAKEUP8s");
  }
  batteryReportCycles++;
}

int32_t BLR = -90000;
void checkBattery()
{
  if (time - BLR > 90000) //only read battery every 90s or so
  {
    unsigned int readings = 0;
    BLR = time;
    for (byte i = 0; i < 10; i++) //take 10 samples, and average
      readings += analogRead(BATT_MONITOR);
    batteryVolts = BATT_FORMULA(readings / 10.0);
  }
}


/*--------------------------------------------------------------------------------------------------
  Send a motion event

*/
void sendEvent() {
  uint8_t dlength, from;
  uint16_t timeout = 10000; // milliseonds

  event.mv = batteryVolts;

  dlength = sizeof(event);
  if (manager.sendtoWait((char *)&event, dlength, SERVER_ADDRESS) == RH_ROUTER_ERROR_NONE) {
    // Now wait for a reply from the gateway
    dlength = sizeof(buf);
    if (manager.recvfromAckTimeout(buf, &dlength, timeout, &from))
    {
      Serial.print(F("Got sendEvent reply from : 0x"));
      Serial.print(from, HEX);
      Serial.print(F(" length "));
      Serial.print(dlength);
      Serial.print(F(": "));
      Serial.println((char*)buf);
    }
    else
    {
      Serial.println(F("sendEvent: No reply from gateway"));
    }
  }
  else {
    Serial.println(F("sendEvent: sendtoWait failed."));
  }
  Serial.flush();
  driver.sleep();  // sleep the radio
}


brolly759

  • Jr. Member
  • **
  • Posts: 64
  • Country: us
Re: LoRa "mesh" with Moteino (non Mega)
« Reply #2 on: April 01, 2018, 10:21:35 PM »
You could always use the LoRa module with an M0 if you run out of space. I believe Adafruit sells a feather board.

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LoRa "mesh" with Moteino (non Mega)
« Reply #3 on: April 01, 2018, 11:10:24 PM »
Maybe replace the flash on the Moteino with an FRAM?

Mark.

LukaQ

  • Sr. Member
  • ****
  • Posts: 302
  • Country: si
Re: LoRa "mesh" with Moteino (non Mega)
« Reply #4 on: April 02, 2018, 01:19:46 AM »
This FRAM does look interesting, I would have application for this (pulse meter)
would I need anything else but changing SPIflash lib. to Fram type?
« Last Edit: April 02, 2018, 01:21:46 AM by LukaQ »

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LoRa "mesh" with Moteino (non Mega)
« Reply #5 on: April 02, 2018, 06:25:41 AM »
I guess so. For the OP's application it may be cheaper to use a simple SPI RAM if it doesn't need to be non-volatile (which I'm assuming it doesn't since this is primarily to store routing tables for meshing, and the megas RAM is obviously non-volatile).

Mark.