A Simple Home Monitoring System...

by Peter Balcombe

OVERVIEW: 

Following on from my RTC backed up MSF clock project, I decided to try out the nRF24L01 radio modules and develop a small home monitoring network, albeit with a lot of help and encouragement from Phil Morris. This network was originally based upon the Maniacbug RF24Network, but has now changed to a Master node initiated command response network based on a Mini Network scheme and sketch templates produced by Phil Morris.

The Mini Network uses a simplified message header embedded within the payload, rather than using a separate network header, with all routing, command and control information contained within just four bytes. Therefore my complete packet containing time, temperature, humidity and pressure data payload can be accommodated using 14 bytes, keeping transmitted packages fairly small. The Mini Network dispenses with the additional overhead of the Maniacbug RF24Network library, using only the RF24 library for radio functions. The Mini Network radio routing functions are included in each node sketch. Each sketch, Master, Branch and Leaf serves a specific purpose.

The network comprises a Master node and up to six 'Branch' nodes, with each 'Branch' acting as a relay to up to five 'Leaf' nodes, giving a maximum network size of 36 'Branch'/'Leaf' nodes. Although each Branch provides up to 5 Leaf nodes, the Branch nodes themselves can also contain code to perform functions.

The node addressing system is octal as follows:

Master

Branch

 Leaf

Functioning Node

0

10

10

Branch (1) 

0 10 11 Branch (1) Leaf (1)

0

10

12

Branch (1) Leaf (2)

0

10

13

Branch (1) Leaf (3)

0

10

14

Branch (1) Leaf (4)

0

10

15

Branch (1) Leaf (5)

Branches (2) to (5) as above

0 60 60 Branch (6)

0

60

61

Branch (6) Leaf (1)

0

60

62

Branch (6) Leaf (2)

0

60

63

Branch (6) Leaf (3)

0

60

64

Branch (6) Leaf (4)

0

60

65

Branch (6) Leaf (5)

The size of the network is essentially restricted by the 8 bit node address limit, whereas the Maniacbug scheme uses 16 bit variables. Use of the octal addressing system limits the address range to two octal numbers/network layers, but still gives more than sufficient nodes for my purpose. Note that the nRF24L01+ modules can communicate via up to 6 'pipelines' simultaneously. Thus the Master can only have up to 6 Branches and each Branch can only have up to 5 Leaf nodes, as each Branch needs to use one of its 6 'pipelines' for communication with the Master node. Each Branch can also be used as a functioning node.

The Master node (node 0) initiates all communication by sending a command to a specific node requesting a specific response. As all command packages contain the package originator node address, the final package destination node address, the command and control data, the originator and the final destination addresses are always retained, allowing the response to be returned to the command originator. The command packages are routed via the appropriate Branch node which then forwards the package to the appropriate Leaf node using the destination node address contained within the package if the Branch is not the final package destination. The command destination node responds to the command, using its node address as the source address, and the command originator node address as the destination address, in the return package. The control bytes contain an 'ACK' or 'NAK' code, allowing the responding node to acknowledge command receipt with an ACK, or with a NAK if 'not ready'.

Differences to note between this Mini Network and the Maniacbug network are:

My project currently comprises a Master node, a MSF synchronised time clock node and 3 temperature sensor nodes, but this will be extended with further temperature sensors, a humidity and pressure sensor in due course to provide a full home thermal monitoring setup.

All nodes are built as stand-alone Atmega based units with Atmega328/P devices used in all except the Master node which uses an Atmega1284 (extra program memory and RAM).

The time and temperature sensor nodes are housed on a 'common' strip board layout complete with nRF24L01+ module, associated 3.3V regulator, temperature sensor (if needed) and serial communications adapter interface. The MSF receiver module can be connected to a 'common' sensor module. Future development of external (to the house) sensors will include a 433MHz receiver add-on to the 'common' sensor module acting as a 'Branch' node. All time/sensor nodes will be housed in small plastic cases and powered using mains powered dc supplies.

I use the TMP36 analogue temperature sensors in a TO-92 package as they are small, easy to use via an analogue input port, and do not have any delay in producing an output signal. Some others, such as the DS18S20 digital sensor, can take up to 750mS to produce an output in parasitic power mode. The TMP36 sensors also work off supplies below 3V and have a measurement range which extends below zero which is good for battery operated sensors or outside air temperature measurement.

The Master node is based on a stand-alone Atmega1284 strip board layout complete with nRF24L01+ module, associated regulator, ICSP connector, MicroSD card interface module, serial communications adapter interface and I2C headers for connection to a DS3231 RTC, 20x4 LCD display and 4x4 keypad. All hardware for this node is also intended to be mounted in a plastic case in due course, with provision to easily remove the SD card for data download/analysis on a PC.All data is recorded on the SD card as a spreadsheet compatible CSV format file.

Although the nRF24L01+ module runs from a 3.3v supply, its interface pins are all 5v signal compatible, so no additional interfacing is required here.

Note that SD cards normally also need a 3.3v supply rather than 5v. Also, unless you have a SD card which has on-board interface level shifters, you will also need to add this functionality between the processor and SD card pins as basic SD card interfaces are not 5V signal compatible as for the nRF24L01+. (See Phil's SD card hardware tutorial for further details and example level shifters.) Be warned that you will fry the standard SD card interfaces if you connect them directly to 5v devices. My hardware implementation used an Adafruit SD card which included both a regulator and level shifters, so I didn't need to add them.

The LCD display currently displays, MSF synchronised time/date and data from 3 temperature sensors. This area will be further developed as more sensors are added.

The Master node samples each sensor at a chosen interval rate and saves this information to the SD card, together with current time/date and each sensor command response status. The sampling cycle rate can be varied from several seconds to several tens of minutes, or longer as required. (Note that all SD cards have a finite limit to the number of times they can be written, so I will keep the sensor sample rate quite low for house thermal monitoring purposes).The SD card writes to a single file called ’logfile.csv’ which is added to each time there is a log event. A log header line is added each time the power is cycled, processor is reset, or the logging is restarted via user keypad input.

SOFTWARE:

There are 4 generic sketches used in this project;

  1. Master node

  2. Time Branch node

  3. Sensor Branch node

  4. Sensor Leaf mode

All sketches use a number of libraries, including the Streaming library for printing debug messages to the serial port - although this can be disabled by making DEBUG = false in each sketch before compiling the code.The SD card library uses Phil Morris' SD_MOD variant which can be obtained from his downloads page. (This variant adds support for the Atmega1284 and more).

Note that in all sketches, the RF24 radio power levels should be configured (in the 'radio.setPALevel(RF24_PA_LOW); default statement within setup() ) as 'LOW' on all modules for localised bench testing to avoid RF signal swamping issues. However, the 'LOW' should be amended to 'HIGH' or 'MAX' as required to achieve reliable communication when deployed to operational measurement locations, depending upon physical separation and building construction that signals have to pass through. Note that both ends of each RF link need to have sufficient power to bridge the gap, so in practice it is easier to make everything the same.

A ‘free memory’ function has been added to each sketch to allow visibility of how much SRAM is being used if DEBUG is true. Note that the Atmega328 has 2K SRAM and the Atmega1284 has 16K bytes.

Master Node (Node 0x00)

This sketch needs an Atmega1284 (or similar resource capability processor) due largely to the resource needs of the SD card. My 4 node handler Master sketch currently compiles to 33,980 bytes and shows 13,648 bytes of memory free, so this sketch will currently not quite fit into an Atmega328.

Branch/Leaf node addresses and commands are stored in arrays which enable each node to be interrogated in any chosen sequence using a for/next loop until all nodes have been addressed. After sending each command, the task manager listens for a response message. Receipt of a valid message within the message timeout period prevents further timeout checks and initiates received data processing, temporary storage in a sensor value array and status flag update.

Received data is processed to generate String format logging data (i.e. "hh:mm:ss" for time, "xx.xx" for temperature) and saved in the appropriate data array location for retrieval by the logging function. Received message handling is currently done on a node by node basis, but could probably be implemented more elegantly, which may particularly be of benefit as more and more nodes are added to the network.

All valid received node data is logged to the log file at the end of the node command cycle, once either a response to the last command has been received, or the final cycle command response timeout has elapsed. The task manager then waits until the command cycle interval has elapsed before starting a new command message cycle.

The sketch first sets up all of the peripherals, initialises the radio, RTC and Time functions, initialises the SD card and writes header information to a new logging file. The sketch allows up to 3 retries if a card error is found during card initialisation. Pressing the ‘*’ key will initiate a SD card initialisation retry, whereas pressing the ‘D’ key will abort further initialisation attempts and disable logging. Once the SD card has been initialised and logging enabled, the user can stop logging by pressing the ‘D’ key and confirm with the ‘*’ key. If the user does not wish to confirm then press any key other than ‘*’ to continue logging. If the user wishes to re-enable logging once stopped, this can be done by pressing the ‘D’ key again, followed by ‘*’ to abort or any other key to restart.. If a new card is inserted, or the logfile.csv file has been deleted from the card, a new logfile.csv file is opened automatically when the card is initialised. The status of the SD card is shown at the end of the 2nd line on the LCD. ‘SD+’ indicates that the card is present and initialised and ‘SD-‘ indicates a card fault (missing/faulty). The card status is updated at start-up, immediately prior to each log event and on completion of the ‘D’ key user input sequence. If the card is removed during logging, this will be detected at the start of the next logging event and logging disabled. Logging may be re-enabled via user keypad input as above.

The main loop acts as the task manager:

  1. Updates the LCD display

  2. Sends commands to each node at the appropriate time

  3. Listens for node responses

  4. Detects response timeout

  5. Processes and temporarily stores received node data

  6. Updates command response status for each node

  7. Logs time, date, node data and node response status to the SD card

  8. Scans the keypad for manual command input

  9. Actions keypad commands

My initial test settings for a 4 node network were a 1.5 second interval between node commands and a  1 minute command cycle interval, giving a node activity flash every 1 minute, whereas in a practical home temperature measurement scenario, the command cycle interval would probably be 10 minutes or more. The message timeout periods can be set individually for each command message, but should be long enough for your node to respond with data. As a guide, a Branch node with the Time function or generating a TMP36 sensor response will have a round trip time of approximately 40mS, whereas with a DS18S20 sensor it could be as long as 800mS. The interval between node commands should also be longer than the maximum node response to allow data to be received in the order expected. However, I think it should be possible (but not tested) for the current Master node response handler to correctly receive and store out-of-sequence responses.

The current uint16_t command response flags variable holds flag bits for up to 16 nodes. A node flag is set when a command is sent and cleared when a valid response is received. As these flags are also logged it is possible to see upon later analysis, which nodes failed to respond and when. 

Time Branch Node (Node 0x10)

This sketch essentially adds the Phil Morris MSF clock sketch, which synchronises the Time library function to MSF time when this is available, into Phil’s' Mini Network Branch node sketch, responding to a SEND_TIME command with the MSF synchronised system time plus ‘ACK’ if MSF synchronised. If no MSF synchronisation has recently been achieved (currently 2 minutes) then a ‘NAK’ response is sent only. Note that the RTC in the Master node will keep better time than the software Time function, thus SEND_TIME responses are only sent if the MSF time synchronism is very recent.

The SendPacket function is common to all sketches as this function constructs the common packet structure, sends the packet and then resets the command and control variables. The DisplayTime and DisplayDate functions provide formatted Serial debugging output if DEBUG is set as true.

Sensor Branch Node (Node 0x20, 0x30 etc.)

This sketch adds reading of the TMP36 analogue temperature sensor, and converting the float temperature reading to an int16_t variable, to Phil’s Mini Network Branch node sketch. A LED flashes briefly each time a node response is sent as confirmation that something is happening.
The Branch node address is amended for each node by altering the MY_NODE variable to the required octal format node number.
Further variants of this sketch will be used to read other sensor types (humidity/pressure) into uint16_t variables in response to SEND_HUMIDITY or SEND_PRESSURE commands as appropriate. Another variant of this sketch will act as an interface to a 433MHz link to more physically remote sensors in due course.

Sensor Leaf Node (Node 0x21, 0x31 etc.)

This sketch is very similar to the Branch node, with the main change being in the radio pipes selection as a Leaf only communicates with its Branch node.
The Leaf node address is amended for each node by altering the MY_NODE variable to the required octal format node number, remembering that a lower level Branch must be present in the network to relay messages to and from the Master node.

HARDWARE:

There are two main circuits, Master and Sensor nodes, with the sensor node having several variants depending on the ‘sensor’ type. Both node types have been built as stand-alone implementations using strip board layouts as shown in the following photographs.

Master Node

This node comprises a main strip board housing the Atmega1284 and reset pushbutton, together with headers for all Atmega pins, micro SD card, ICSP, FTDI interface, RTC/external I2C modules and power. The nRF24L01+ module is mounted, together with its local 3.3V supply regulator on a small daughter board which plugs into the Atmega pin headers. The unit is currently powered from an external 5V supply but a 5V regulator could be accommodated on the board if desired and this is shown on the Fritzing arrangement.

The three I2C headers allow connection to the I2C 20x4 LCD display, a 4x4 membrane keypad via a PCF8274 I2C interface mounted on another small strip board, and the DS3231 RTC module.

The following Fritzing breadboard layout gives an idea of the basic circuit connections excluding the NRF24L01, SD card and ICSP headers plus Atmega1284 pin headers used by the NRF24L01 plug-in strip board. See the tables below for nRF24L01+ and ICSP connections for an Atmega1284 based implementation. See Phil’s hardware tutorial pages for further information on the nRF24L01 modules and SD cards.

Atmega1284-nRF24L01 connection

Atmega1284 I/O pin

nRF24L01 Pin

GND

11

GND

1

+3.3V

-

VCC

2

D2

3

CE

3

D3

4

CSN

4

SCK

8

SCK

5

MOSI

6

MOSI

6

MISO

7

MISO

7

-

-

INT

8

 ICSP Header

MISO

O

O

VCC

SCK

O

O

MOSI

RST

O

O

GND

Sensor Node

The basic sensor node comprises a main strip board unit housing the Atmega328, together with headers for the nRF24L01+ module, ICSP, FTDI interface and 5V power. A LED is fitted to Atmega pin 13 (D7) for use by the sensor sketches. The same hardware is used for both ‘Branch’ and ‘Leaf’ node types.The analogue TMP36 temperature sensor is fitted to most sensor nodes adjacent to the A0 input port. The 3.3V regulator required by the radio module is fitted adjacent to the ICSP header. Again, the unit is currently powered from an external 5V supply but a 5V regulator could be accommodated on the board if desired and is shown in the Fritzing arrangement.

The MSF time sensor board is a variant of the basic Sensor node strip board which deletes the TMP36 sensor and adds a 3 pin header to provide a 5V supply plus connection to the INT1 pin (Atmega pin 6).The MSF receiver module (and associated ferrite aerial) is mounted remotely from the main strip board to reduce processor interference. I plug the receiver module into a small interface strip board which also contains a 3.3V regulator and 220uF smoothing capacitor to provide a suitable supply.

The ferrite aerial wires are connected to the receiver A1 and A2 pads (either way round). Connect +3.3V to the Vdd pad, 0V to the GND pad and connect the TCON pad to the Atmega INT1 pin. Leave PON unconnected. (See my MSF synchronised RTC clock project or Phil’s MSF hardware pages for further details).

The following Fritzing breadboard layout gives an idea of the circuit connections, noting that the nRF24L01+ header is actually a single 8 pin double row socket header rather than 2 separate 4 way headers as shown. Note that the ICSP header is not shown in the Fritzing sketch. See the table above for ICSP connections and the table below for nRF24L01+ connections with an Atmega328 based implementation. See Phil’s hardware tutorial pages for further information on the nRF24L01 modules.

Atmega328-nRF24L01 connection

Atmega I/O pin

nRF24L01 Pin

GND

8

GND

1

+3.3V

-

VCC

2

D8

14

CE

3

D9

15

CSN

4

SCK

19

SCK

5

MOSI

17

MOSI

6

MISO

18

MISO

7

-

-

INT

8