Tuesday, January 14, 2014

Node@Home communication protocol draft

I have been pondering on creating a home network of nodes using cheap slaves and a more powerful master. Since the name did not come up in any Google search I settled upon Node@Home.

My idea is to have gadgets spread around the house/perimeter that can report sensor data to a central station and perform certain actions. It will be first used to start the [electrical] heating remotely, check rooms temperature, actuate the blinds on the outside, log the voltage measured by the home-made PSU, start or unblock the Roomba, etc.

I am sure that with creating an affordable master node (based on Stellaris Launchpad or Raspberry Pi) and disposable slave nodes will make everyone want to have these things around the house.

The minimum requirements for the nodes will be a baseline microcontroller (PIC10/12F, MSP430F, <1$ each) and an NRF24L01 radio transceiver (1-4$). The power of the network will be in the protocol requirements and the software.

UPDATE: the draft below is wrong because I assumed broadcasting was possible with the NRF24 units, which is not. I have written a new one in the mean time but I did not have time to implement a proof-of-concept, so I'm not publishing it until it is proven.
However, the payload section will remain mostly as-is.

Here is my first draft for this, loosely based on the BMW IBUS protocol:

The master node will be tied either directly to the LAN or via a USB serial connection to a master computing device.
The master computing device can serve web pages, gather data (from web router for example) and provide a user interface.
The master node will have all necessary communication modules, at least Bluetooth and NRF24L01.
One master defined by 0xC7 header. Additional masters can be later added by increasing this id though it might not be needed.
The master can also do protocol translation which enables it to act as a router between communication interfaces.

The nodes will contain the minimum/cheapest communication modules, NRF24L01 being the preferred one.
All slaves transmit data using the 0xCC header. Some slaves might be read-only, like alarm sensors or bench PSU.
Data can be polled from the nodes by the master or the nodes can push data themselves in a redundancy format (e.g. 10x repetition).
This enables low-cost low-power chip solutions like MSP430F and PIC10/12F.

All communication which does not successfully match the checksum is discarded without any acknowledgement.
No immediacy is required and no critical data must be passed as it should function on a best-effort basis.
A data rate of 19200bps is considered suitable for basic data and text transmission and can easily by done by software UART.

Additional nice-to-have: dynamic baud rate, OTA firmware updates, scripting for smarter nodes.

Example nodes: heating control (temp sensor + servo), multimeter/battery monitor, weather station, remote display, buzzer, IR transmitter.


Packet definition:
2b header C7 for master: N(ode)=12=C.H(home)=7=7 or CC for nodes
2b payload size w/o header & checksum
xxb payload
1b checksum = sum of payload


Default messaging constants:
0x00 means undefined/unimplemented
0xFF means any/broadcast
0x4B = K means OK or ACK
0x52 = R means error, NACK
0x4E = N means N/A, not implemented or not available
K or R can have additional data bytes (human-readable error code for example)

Master payload header:
4b request id (incrementing)
1b slave architecture (0x00=specific node id, AVR, MSP430, ARM, ...0xFF=any)
1b node type (MSB node id, thermo, generic i/o, generic display, ...)
1b reserved (LSB node id)
1b request type (identify, command, firmware upload, ...)
xxb data (display string, firmware stuff, ...)


Slave payload header:
1b response type (poll response, push, ...)
4b request id (first 2b can be 0x00 0x00 for 8/16-bit arch) for poll responses
2b node id (can be randomly generated at powerup by user action)
xxb data


Master sends the same package 10x or until it receives an ACK. FIFO message queue size for master is 255.
Expired messages get deleted unless they have a persistent flag in which case they are put back at the end.
First the master tries to send all messages in burst, then it iterates through the remaining ones with a random delay.

For broadcasted responses slaves wait a random amount of time: random(255) * 10ms - maximum 2.5s.
For push-only node message they get sent 10x with the above randomization.

Obviously nodes have to be designed in such a way as to handle duplicated requests.
Either save the id or make sure the actions have only one result (e.g. no increment operation, only set)

Example broadcast identification request:
- master sends: 0xC7 0x08 nnnn   0xFF   x   x   0x1     0xm 
                hdr  size reqid  bcast N/A N/A  ident chksum
- slaves respond after random delay:
0xCC 0x0A 0x01  nnnn  0xmm 0xk 0xp 0x0q    0xj 0xrr
 hdr size respo reqid n.id arc typ p.count ver chcksum


Request type:
0x01 - identify request
Requested nodes (or broadcast) must respond with
//1b node arch
//1b node type
//1b number of peripherals
//1b firmware version

0x02 + 0xn - identify peripheral; 2 data bytes represents peripheral id
nodes respond with:
//2b peripheral type
//1b peripheral description length
//nn bytes peripheral description

0x03 + 0xnn - poll peripheral data
//n bytes node response

0x04 + n bytes - set peripheral
//node response is K (0x4B) or R (0x52) or N (0x4E), optional code

0x05 - get node string description
//node response is the rest of the payload

0x06 + n bytes - set node string description
//TBD - the node can save the description into RAM or ROM, depending on implementation
//node response is K (0x4B) or R (0x52) or N (0x4E), optional code


Peripherals type:
0x01 - 8bit GPIO
0x02 - 16bit GPIO
0x03 - temperature DS18B20
0x04 - generic/voltage ADC, 1 byte
0x05 - generic/voltage ADC, 2 bytes
0x06 - generic/voltage ADC, 4 bytes
0x07 - servo output - TBD
0x08 - humidity - TBD
0x09 - light - TBD
0x0A - generic text display (like HD44780) - TBD chars, lines, ...
0x0B - graphic display - TBD resolution, colors
0x0C - buzzer output
0x0E - IR sensor (remote)
0x0F - IR transmitter (remote)
- other sensor types: accelerometer, I2C, SPI, raw, Roomba


No comments:

Post a Comment