Pin Sleep Xbee with Arduino Host

Making it work.

I got everything to function with a rather messy board setup as shown below.

The output from the Arduino shows the delta T between messages received from the end-devices.  It is pretty close to the calculated ones. I will change the duration to be 15 minutes later on but for debugging purposes 10s intervals for pin sleep is tolerable.


 Code

The following are the libraries were referenced.

Arduino library for communicating with XBees in API mode – I used both Java and C++ versions for this.

Standard Template library (STL) for AVR – I wanted some maps and other stuff in the dev environment.

Streaming C++ style Output – print and println gets to be a pain after a while

Ardunio Modbus Slave – I used this for my energy monitoring project as well and hacked in a modbus function 6. Since then, a new library that includes function 6 has been deployed, but I still used the older version as I wrapped the C++ class – SerialModbusSlave and did not feel like manually merging code.

 HardwareSerial

I leveraged the serial ports available in the Mega2560 and created global variables to reference instances of the serial port as follows:

HardwareSerial gModbusPort = Serial;
HardwareSerial gDebugPort = Serial2;
HardwareSerial gXBeePort = Serial1;

Which allowed me to do things like the following:

  xbee.setSerial( gXBeePort);
  xbee.begin(BAUD_RATE);

  gDebugPort.begin(BAUD_RATE);

  // TODO: send from host
  setTime( 1308482002 );  
  gModbusSlave.setRegisterBuffer( gModbusRegs, MAX_MODBUS_REGS  );
  gModbusSlave.init( &gModbusPort, MOD_SLAVE_ID, BAUD_RATE, 'n', 0);

I can change ports around in one spot in the code rather than find an replace things.

I opted to over design things a bit as I wanted to avoid changing the code later on as tacit information tends to be forgotten over time. What I wanted to do is be able to provision new end devices without changing the arduino code and follow a simple 4 step process:

  1. update to appropriate firmware in XBee, set Pan ID, and API mode 2
  2. utilize the home grown Java app to set up the details such as IO types and lines  ( I am thinking of adding a clone function to make this even simpler)
  3. wire up xbee related circuitry
  4. provision the end device in the Arduino via Mango HMI over Modbus

The following illustrates the concept in a non-formal way of describing software. When a ioresponse is received from an end device I look up the corresponding meshdevice entry in map using the string representation of the address64. I was thinking of using int64_t  type rather than a string as the string takes more space but that is not at a premium at this point.

The address64 string for managed end devices are stored in eeprom and loaded on setup(). Provisioning of end devices are sent over modbus from the HMI host and written to eeprom as well. Yes overkill, but t I want to evolve the system and focus on some abstraction to allow the evolution the meshdevice representation. All the smarts to evolve will be confined in one class. The tacit information like how to provision and communicate with the HMI, etc. will hopefilly remain static.

Map of Meshdevices

A map of using the STL for AVR to reference the MeshDevice is as follows:

// a place to reference devices and corresponding data
typedef std::map<String,MeshDevice> RemoteDevicesMapType;

RemoteDevicesMapType gRemoteDevices;

And updating meshdevices is coded as follows and will change later on as the error handling is uber weak.

void refreshDeviceReference( ZBRxIoSampleResponse aIOSample ) {

  MeshDevice lCandidateDevice;

  RemoteDevicesMapType::iterator lItr;
  std::pair<std::map<String,MeshDevice>::iterator,bool> lRetVal;

  String lAddress64 = String((long) aIOSample.getRemoteAddress64().getMsb(),HEX)  
                      + String((long) aIOSample.getRemoteAddress64().getLsb(),HEX);

  lItr = gRemoteDevices.find( lAddress64 );
  if( lItr != gRemoteDevices.end())
  {
    lItr->second.beginTransaction();

    for (int i = 0; i <= MAX_ANALOG_INPUTS; i++) {
      if (aIOSample.isAnalogEnabled(i))
        lItr->second.setAnalogInput( i, aIOSample.getAnalog(i) );
    }

    for (int i = 0; i <= MAX_DIGITAL_INPUTS; i++) {
      if (aIOSample.isDigitalEnabled(i))
        lItr->second.setDigitalInput( i, aIOSample.isDigitalOn(i) );
    }    

    // lItr->second.dumpContent( gDebugPort );
    lItr->second.endTransaction();
    gDebugPort << "Received I/O Sample from: " << lAddress64 <<" detalt="
               << lItr->second.getDeltaT() << " ms" << endl;

  }
  else
    gDebugPort.println( "Not Found : " + lAddress64 );
}

Modbus Register Buffer

Lastly the mapping to modbus style registers are set up as clusters for each device and terminated with a set of register to accept commands and address64 strings from the host. The code for it is rather simple and I will shoehorn this later on. Up to 13 discrete (digital) and 5 analog I/O are reserved for each device. What is used depends on how the XBee device is configured which is explained in the XBee datasheet 90000976_D Datasheet

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The prototype basically implemented the following data flow model. The issue for me is battery powered end device is not green enough of a solution for me.  I’m thinking of exploring energy harvesting to help things along. The plan was to also send battery voltage level on the end device to the SCADA host to generate low battery alarms. Still, it would be nicer to tap into ambient environment (vibration, etc) to generate energy to help power the end device. This will be explored later.