The #HELO Protocol

A very simple text-based protocol for IoT devices, requiring very little configuration, intended to be broadcast in UDP packets.

By default, use UDP port 16378.

The simplest form

Messages consist of the line "#HELO" optionally followed by a space and a resource path, any message header lines, and, if there is non-empty payload, a blank line, and then the message payload, which extends to the end of the packet and can be in any format.

'resource path' indicates the name of the resource that this message is about. It could be a URI, a device-local path starting with "/", or a UNC-like path of the form "//" + device name + "/" + path. If no path is given, it is implied to be "/".

Message headers are of the form of any non-whitespace characters, and then, if there is any value, a space, and then the value. Values containing linefeeds can be represented by following the linefeed with a tab character. The tab will not be part of the value, but marks a continuation of the previous value (this is the same line continuation rule as used by TEF).

Lines are terminated by a single linefeed character (0x0A). The "#HELO" line and any message header lines should always end with a linefeed, even if they are at the end of the message.

Lines beginning with "#" are special directives. For now, none are defined. You just can't have headers that start with that character.

By convention, the payload is in the same format as the headers, providing values for various device properties relative to the resource path. e.g. if the resource path is "//my-cool-sensor/bus1/" and the payload contains "subdevice0/reading 123.45", then that can be interpreted as providing the value 123.45 for the fully-qualified property //my-cool-sensor/bus1/subdevice0/reading.

Examples:

The simplest possible message, which just announces that there is a device:

#HELO

Hypothetical message from a combined temperature/humidity sensor + relay device, which uses its own MAC address as its name:

#HELO //ab-cd-ef-01-23-45/

temperature1 20C
humidity1 35%
temperature2 25C
humidity2 33%
switch1/state on
switch2/state off

Room for extension

The following are suggestions. Nothing is 'standardized' yet.

Fragmented property values

Payload might contain some directive indicating whether this packet contains only a patch to be applied to the property-value map for this resource, or if it is comprehensive.

Let's say that "#clear" should be interpreted as 'forget everything you know about this resource', and everything else is implicitly a patch.

Versioning

Could be accomplished by appending something to the "#HELO" token. Maybe a slash followed by a version number?

Requests

Would have semantics similar to their HTTP cousins. GET, PUT, and PATCH being especially useful.

The method could follow any version number in the initial token.

e.g. to tell a device to turn off a switch, you might send:

#HELO/1234/PUT /switch1

off

Authentication

To prevent any old Joe Schmoe from turning your lights on and off, but to keep things simple, I would probably use some symmetric key-based authentication header, which might contain a hash of the rest of the message + a shared secret key. A minimum nonce would be sent by the device to prevent replay attacks. The exchange would look something like:

Broadcast from device:

#HELO /authentication

/scheme FooAuth
/min-nonce 12345

Sent to the device by someone wanting to turn on the switch:

#HELO/PUT /switch1/state
authorization FooAuth 12346;asd234123

on

Response metadata

A status header can mirror that of HTTP to respond to specific requests.

Request:

#HELO/GET /something
reqid jeffk123

Response:

#HELO /something
re-reqid jeffk123
status 404

There is no such resource as '/something' here!

Changelog