Tuesday, January 16, 2018

Wireless node configuration.

Wireless nodes are part of OHS ecosystem. They serve as source of data from sensors, and as receivers for inputs. Inputs represents relays or other devices waiting for incoming commands. If you want to connect wireless node to gateway you need to set it up first. Start with download of example sketch from GitHub. Here is code for hardware version 1.4 https://github.com/vysocan/remote_1_4_RFM69. If you have on hand version with on-board temperature sensor and USB charging circuit then you can use the code almost without change. Basically you need to modify just the setting for radio module. Here is the part for radio

// Radio
#define NODEID      14
#define NETWORKID   100
#define GATEWAYID   1
#define FREQUENCY   RF69_868MHZ //Match this with the version of your gateway 
#define KEY         "ABCDABCDABCDABCD" //has to be same 16 characters/bytes on all nodes, not more not less!
#define ENABLE_ATC  //comment out this line to disable AUTO TRANSMISSION CONTROL
#define ATC_RSSI -75 

From this you need to only change following:

NODEID      2     // is number from 2 .. 250, do not number the nodes with same NODEID!
FREQUENCY   RF69_868MHZ // depends on your country, leave it as is or put RF69_915MHZ
KEY         "ABCDABCDABCDABCD" // needs to match the KEY of gateway.
ENABLE_ATC        // leave as is for battery powered nodes
ATC_RSSI -75      // threshold for AUTO TRANSMISSION CONTROL, you can safely leave as it is.

To start with minimal changes only, change just NODEID to be unique and KEY to match the one from gateway.

Wireless nodes are programmable, as gateway, with 3V3 FTDI 6pin USB to Serial programmer. They can be also powered from the programmer, that means you do not need a battery or charger plugged in while experimenting. To upload your sketch into board you have choose the right board target:
Select Tools > Board menu > Arduino Pro or Pro Mini, then choose Tools > Processors > ATmega328P (5V / 16Mhz)

All nodes run on 3V3 but on 16Mhz, as there is no such option choose  always (5V / 16Mhz), it will not do any harm. But FTDI programmer should be always set to 3V3 or the radio module will be damaged!

If all is set, you should see four new sensors in Node tab of gateway web interface. Wireless node then report temperature, battery voltage if battery is connected, charging status and own radio power level. Power level is useful to see how good the signal is when Auto Transmission Control is enabled, lower is better.

If you want to add new hardware to any node you need to create a default configuration for it in software. Assume that you want to add another temperature sensor to above mentioned four. First locate and change the total number of elements on this node, highlighted as bold:

// Configuration struct
struct config_t {
  uint16_t version;
  char     reg[REG_LEN * 5]; // Number of elements on this node
} conf; 

Then locate function setDefault(), you can see it is starting with following:

conf.version = VERSION;   // Change VERSION to force EEPROM load
conf.reg[0]  = 'S';       // Sensor
conf.reg[1]  = 'T';       // Temperature
conf.reg[2]  = 0;         // Local address
conf.reg[3]  = B00000000; // Default setting
conf.reg[4]  = B00011110; // Default setting, group=16, disabled
for (uint8_t ii=0; ii < 17; ii++){ conf.reg[5+ii] = 0;}

conf.version is place holder for node EEPROM setting and is to be left as is. But conf.reg[0..20] is place for default element configuration. Every element size is 21 bytes and their meaning is as follows:
  • 0  means the major element type. First letter of Sensor, Input, Key or Zone.
  • 1 is minor type of element. First letter of iButton, Temperature, Humidity, Pressure, Voltage, Battery, Digital, Analog, Float, TX_Power or Gas. If others are needed they should be added to GW software, or they will be reported as Unknown.
  • 2 Is local address in range from 0..255. In case you need to have more then one device of same type.
  • 3..4 are default configuration place holder, it is always as is. In real it holds various status flags of current element, but it is configured through web interface of gateway after it connects.
  • 5..20 are storing element name. Here set to null, as real name is received from web interface of gateway.
To go back to adding a new element you need to add bellow 21 bytes to the end of  setDefault() function and increase the number in [] accordingly:

conf.reg[84] = 'S';       // Sensor
conf.reg[85] = 'T';       // Temperature
conf.reg[86] = 1;         // Local address
conf.reg[87] = B00000000; // Default setting
conf.reg[88] = B00011110; // Default setting, group=16, disabled
for (uint8_t ii=0; ii < 17; ii++){ conf.reg[89+ii] = 0;}

Notice the local address is increased by one. Last thing after adding new element is to force the node to reset its EEPROM configuration and load the data from setDefault(). This is done by increasing the VERSION in top of sketch:
#define VERSION     140 // <- increase by 1

If you upload above changes to node gateway should recognize the new sensor and you will see it in Nodes tab. You can then configure it as any other element. Gateway will send the configuration back node and it will store it in its own EEPROM. This configuration persist even if you power off the node.

Next thing would be to actually add the code to handle your new sensor data. I skip the part of how you get the temperature value, as it will depend on which temperature sensor you are actually using. And I go directly to sending. Gateway receives various packets, but similar to registration structure mentioned above, sensor data need to follow data structure:
  • 0 identifies type of payload. First letter of  Sensor, Input or Zone.
  • 1 is minor type of element as defined in setDefault() function.
  • 2 Is local address as defined in setDefault() function.
  • 3..6 are the actual data.
For example following code:

// Temperature 
u.fval = (((float)analogRead(A6) * 0.003223)-0.5)*100; 
msg[0] = 'S'; // Sensor
msg[1] = 'T'; // Temperature
msg[2] = 0;   // local address
msg[3] = u.b[0]; msg[4] = u.b[1]; msg[5] = u.b[2]; msg[6] = u.b[3];
// Send to GW 
radio.sendWithRetry(GATEWAYID, msg, 7); 

It will read the analog value from A6 pin, then do some necessary calculation depending on this exact temperature sensor, and store it in special float variable u.fval. All data for sensors and inputs are type float, that is they are 4 bytes long. First part of msg[0..2] create the header describing the source of data and msg[3..6] reads the data converted from float u.fval to 4x u.b[0..3] byte values. Calling radio.sendWithRetry then sends the data stored in msg array to gateway. Length of data is set to 7 as it contains bytes stored in array msg[0..6].
In one packet you can send more then one payload of same major type, here as 'S' in msg[0]. As shown here:

// Temperature 
u.fval = (((float)analogRead(A6) * 0.003223)-0.5)*100; 
msg[0] = 'S'; // Sensor
msg[1] = 'T'; // Temperature
msg[2] = 0;   // local address
msg[3] = u.b[0]; msg[4] = u.b[1]; msg[5] = u.b[2]; msg[6] = u.b[3];
// BATT Voltage 
u.fval = 0.0064453125 * (float)analogRead(A7); // Voltage divider 2:1
msg[7] = 'V'; // Voltage
msg[8] = 0;   // local address
msg[9] = u.b[0]; msg[10] = u.b[1]; msg[11] = u.b[2]; msg[12] = u.b[3];
// Send to GW 
radio.sendWithRetry(GATEWAYID, msg, 13); 

All that is needed, is to prepare the data in msg buffer and increase the length of message. Radio message length cannot exceed 62 bytes, or the actual size of bytes allocated in sketch for array msg[].

And that should be all :).