mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-12 09:36:59 +00:00
Split the plugin related substitutions into separate files (per 10) to speed-up building docs. Please note the use of indirect paths used in includes, needed to link those replacements from other directories.
264 lines
7.1 KiB
ReStructuredText
264 lines
7.1 KiB
ReStructuredText
.. include:: _controller_substitutions.repl
|
||
|
||
.. _C013_page:
|
||
|
||
|C013_typename|
|
||
==================================================
|
||
|
||
|C013_shortinfo|
|
||
|
||
Controller details
|
||
------------------
|
||
|
||
Type: |C013_type|
|
||
|
||
Name: |C013_name|
|
||
|
||
Status: |C013_status|
|
||
|
||
GitHub: |C013_github|_
|
||
|
||
Maintainer: |C013_maintainer|
|
||
|
||
Change log
|
||
----------
|
||
|
||
.. versionchanged:: 2.0
|
||
...
|
||
|
||
|improved|
|
||
Implementation of secure communication and check for valid data.
|
||
|
||
.. versionadded:: 1.0
|
||
...
|
||
|
||
|added|
|
||
Initial release version.
|
||
|
||
Description
|
||
-----------
|
||
|
||
ESPEasy is able to communicate between nodes itself.
|
||
It is an IANA registered service: `espeasy-p2p <https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=8266#ESPeasy>`_
|
||
|
||
* Service Name: espeasy-p2p
|
||
* Port Number: 8266
|
||
* Transport Protocol: UDP
|
||
* Description: ESPeasy peer-2-peer communication
|
||
* Registration date: 2018-11-28
|
||
|
||
This protocol is targeted specific for use by ESPeasy to let ESPeasy nodes
|
||
communicate with each other to create a big swarm of nodes working together
|
||
without the need for a hosted service like MQTT, which needs a central broker.
|
||
|
||
It is currently used for:
|
||
|
||
* Discovery of nodes
|
||
* Sharing sensor data among nodes
|
||
|
||
Later updates may add:
|
||
|
||
* Distribution of settings
|
||
* Sending commands
|
||
|
||
Sending & Known Nodes
|
||
---------------------
|
||
|
||
ESPEasy keeps track of all nodes advertising themselves via Sysinfo messages.
|
||
|
||
This knowledge is kept in a ``NodeStruct`` for at least 10 minutes.
|
||
If a node is not sending a Sysinfo message in this period, it will be removed from the list.
|
||
|
||
Data Format Versions
|
||
--------------------
|
||
|
||
During the IANA port assignment assessment, a number of issues were pointed out by their experts.
|
||
|
||
* Versioning
|
||
* Security
|
||
* Data validation
|
||
* Traffic limiting and congestion handling
|
||
|
||
There are now 2 versions available:
|
||
|
||
* Version "0" - No security, no data validation.
|
||
* Version "1" - Introduced in ESPeasy build <???>
|
||
|
||
Data Format Version 0
|
||
---------------------
|
||
|
||
Sending and receiving is causing issues when the swarm of nodes increases.
|
||
|
||
* All nodes with this service enabled will advertise their presence every 30 seconds via broadcast
|
||
* Nodes can not subscribe to receiving sensor data updates
|
||
* Non broadcast messages are sent to each individual known node, regardless if the receiving node will use the data
|
||
* Sensor Data messages are sent to each individual known node
|
||
* Sensor Info updates are sent to each individual known node when a plugin coupled to this plugin is saved.
|
||
|
||
Of each known node the following data is kept:
|
||
|
||
.. code-block:: C++
|
||
|
||
struct NodeStruct
|
||
{
|
||
String nodeName;
|
||
byte ip[4];
|
||
uint16_t build;
|
||
byte age;
|
||
byte nodeType;
|
||
};
|
||
|
||
The key to index this ``NodeStruct`` is the nodes unit number.
|
||
|
||
ASCII Data
|
||
~~~~~~~~~~
|
||
|
||
Command Message
|
||
***************
|
||
|
||
First byte is not 0xFF.
|
||
|
||
The entire message processed as a command like this:
|
||
|
||
.. code-block:: C++
|
||
|
||
packetBuffer[len] = 0;
|
||
String request = &packetBuffer[0];
|
||
struct EventStruct TempEvent;
|
||
parseCommandString(&TempEvent, request);
|
||
TempEvent.Source = VALUE_SOURCE_SYSTEM;
|
||
if (!PluginCall(PLUGIN_WRITE, &TempEvent, request)) {
|
||
ExecuteCommand(VALUE_SOURCE_SYSTEM, &packetBuffer[0]);
|
||
}
|
||
|
||
As can be seen, no checks for size, and it is just expected to be a valid ESPeasy command.
|
||
Also no check to see if the command is supported by the receiving end and no feedback to the sender.
|
||
|
||
Binary Data
|
||
~~~~~~~~~~~
|
||
|
||
Binary data is marked with the first byte 0xFF.
|
||
|
||
On the receiving end, it is packed in an event in the ``Data`` field and processed like this:
|
||
|
||
.. code-block:: C++
|
||
|
||
struct EventStruct TempEvent;
|
||
TempEvent.Data = reinterpret_cast<byte*>(&packetBuffer[0]);
|
||
TempEvent.Par1 = remoteIP[3];
|
||
TempEvent.Par2 = len;
|
||
PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString);
|
||
CPluginCall(CPLUGIN_UDP_IN, &TempEvent);
|
||
|
||
N.B. only the controller C013 implements code for handling UDP data.
|
||
|
||
Message types supported, determined by the 2nd byte:
|
||
|
||
* 1: Sysinfo message
|
||
* 2: Sensor info pull request (not implemented)
|
||
* 3: Sensor info
|
||
* 4: Sensor data pull request (not implemented)
|
||
* 5: Sensor data
|
||
|
||
Sysinfo Message
|
||
***************
|
||
|
||
There are 2 types of Sysinfo messages, a standard and an extended message.
|
||
The extended message starts with the same information as the standard one.
|
||
|
||
Standard Sysinfo message (13 bytes):
|
||
|
||
* 2 bytes marker (255 , 1)
|
||
* 6 byte MAC address
|
||
* 4 byte IP address
|
||
* 1 byte unit number
|
||
|
||
Extended Sysinfo message (13 + 28 = 41 bytes):
|
||
|
||
* 2 bytes ESPeasy data version number (LSB, MSB)
|
||
* 25 bytes node name
|
||
* 1 byte node type
|
||
|
||
The node type is defined as:
|
||
|
||
* 1 = "ESP Easy"
|
||
* 17 = "ESP Easy Mega"
|
||
* 33 = "ESP Easy 32"
|
||
* 65 = "Arduino Easy"
|
||
* 81 = "Nano Easy"
|
||
|
||
Sensor Info message
|
||
*******************
|
||
|
||
Sensor Info messages are just a description of a shared sensor.
|
||
It contains some information to setup a new sensor on the receiving end.
|
||
|
||
These messages are just a serialized byte stream of ``struct C013_SensorInfoStruct`` .
|
||
|
||
.. code-block:: C++
|
||
|
||
struct C013_SensorInfoStruct
|
||
{
|
||
byte header = 255;
|
||
byte ID = 3;
|
||
byte sourcelUnit;
|
||
byte destUnit;
|
||
byte sourceTaskIndex;
|
||
byte destTaskIndex;
|
||
byte deviceNumber;
|
||
char taskName[26];
|
||
char ValueNames[VARS_PER_TASK][26];
|
||
};
|
||
|
||
|
||
Sensor Data message
|
||
*******************
|
||
|
||
|
||
These messages are just a serialized byte stream of ``struct C013_SensorDataStruct`` .
|
||
|
||
.. code-block:: C++
|
||
|
||
struct C013_SensorDataStruct
|
||
{
|
||
byte header = 255;
|
||
byte ID = 5;
|
||
byte sourcelUnit;
|
||
byte destUnit;
|
||
byte sourceTaskIndex;
|
||
byte destTaskIndex;
|
||
float Values[VARS_PER_TASK];
|
||
};
|
||
|
||
|
||
Data Format Version 1
|
||
---------------------
|
||
|
||
This version remains compatible with version 0 for backwards compatibility.
|
||
It is using the "next" unused marker.
|
||
|
||
All messages will have a standard packet data format:
|
||
|
||
* 2 bytes Marker (255 , 6)
|
||
* 2 bytes Version => also determines data offset (header length)
|
||
* 2 bytes Message type
|
||
* 2 bytes Size of data block in "N" blocks of 16 bytes
|
||
* 2 bytes Key/group selector
|
||
* 2 bytes Sequence number
|
||
* (16 x N) bytes Data block AES encrypted data (including 2 bytes checksum)
|
||
* 2 bytes Packet checksum
|
||
|
||
This allows to:
|
||
|
||
* Distinguish data format versions
|
||
* Filter on message type before allocating large buffers
|
||
* Use multiple (pre-shared) encryption keys to have several levels of security or just several groups.
|
||
* Validate correct transmission of packet (last 2 checksum bytes) before decrypting data.
|
||
* Allow for larger messages to be sent in sequences. (e.g. firmware upgrades?)
|
||
* Validate sender and content of data block, since it contains a checksum too, which is part of the encrypted data block.
|
||
|
||
Since AES has a block size of 16 bytes (128 bit), the size of the data block is defined as a block of 16 bytes.
|
||
This allows up-to 1 MB of messages. (2^16 * 2^4 = 2^20)
|
||
An UDP datagram sent over IPv4 cannot exceed 65,507 bytes (65,535 − 8 byte UDP header − 20 byte IP header).
|
||
In IPv6 jumbograms it is possible to have UDP packets of size greater than 65,535 bytes.
|