Packet Transport Component
The purpose of this component is to allow ESPHome nodes to directly communicate with each over a communication channel. It permits the state of sensors and binary sensors to be transmitted from one node to another, without the need for a central server or broker. The actual transport channel is provided by another component. Currently the supported transports are Espnow, Sx126X, Sx127X, Uart and Udp.
Nodes may be providers which transmit or broadcast sensor data, or consumers which receive sensor data from one or more providers. A node may be both a provider and a consumer. Optional security is provided by one or more of:
- encryption using a shared secret key
- a rolling code
- a challenge-response (ping-pong) key
Example Configuration
Section titled “Example Configuration”# Example configuration entrypacket_transport: platform: ... update_interval: 5s encryption: "REPLACEME" rolling_code_enable: true binary_sensors: - binary_sensor_id1 sensors: - sensor_id1 - id: sensor_id2 broadcast_id: different_id providers: - name: device1-name encryption: "REPLACEME"
sensor: - platform: packet_transport provider: device1-name id: local_sensor_id remote_id: some_sensor_id
binary_sensor: - platform: packet_transport provider: device2-name type: data # Optional, defaults to 'data' id: other_binary_sensor_id # also used as remote_id
- platform: packet_transport provider: device1-name type: status name: Device 1 connection statusConfiguration variables
Section titled “Configuration variables”-
id (Optional, ID): Manually specify the ID used for code generation.
-
update_interval (Optional, Time): Interval between full broadcasts. Defaults to 15s.
-
sensors (Optional, list): A list of sensor IDs to be broadcast. Each entry may be just the sensor id, or may set a different id to be broadcast.
- id (Required, ID): The id of the sensor to be used
- broadcast_id (Optional, string): The id to be used for this sensor in the broadcast. Defaults to the same as the internal id.
-
binary_sensors (Optional, list): A list of binary sensor IDs to be broadcast.
- id (Required, ID): The id of the binary sensor to be used
- broadcast_id (Optional, string): The id to be used for this binary sensor in the broadcast. Defaults to the same as the internal id.
-
encryption (Optional, string): The encryption key to use when broadcasting. Default is no encryption. This may be any string, and will be hashed to form a 256 bit key.
-
rolling_code_enable (Optional, boolean): Enables a rolling code to be included in all broadcasts. Requires
encryptionto be set. Defaults tofalse. Can be set only on the provider side. -
ping_pong_enable (Optional, boolean): When set, requires encrypted providers to include a nonce generated by this device in broadcasts. Defaults to
false. Can be set only on the consumer side. -
ping_pong_recycle_time (Optional, Time): Controls how often the ping-pong key is regenerated. Requires
ping_pong_enableto be set. Defaults to 10 minutes. Can be set only on the consumer side. -
providers (Optional, list): A list of provider device names and optionally their secret encryption keys.
- name (Required, string): The device name of the provider.
- encryption (Optional, string): The provider’s encryption key.
Wherever a provider name is required, this should be the node name configured in the esphome: block.
This component supports multiple configurations, making it possible to differentiate between consumers when providing data to them, or providers if they are multiple.
When receiving data in such a configuration, sensors need a transport_id configuration item to know where to expect data to come from.
Reliability
Section titled “Reliability”The reliability of the transmission is dependent on the underlying transport.
Security
Section titled “Security”By default there is no security - all data is transmitted in clear text on the network. This would be appropriate for non-sensitive sensor data or perhaps on a fully secured wired network. For other cases the data can be encrypted by providing an encryption key, which is shared between the provider and consumer.
Encryption alone ensures that data cannot be read in transit and protects against spoofing of data, but does not protect against replay attacks (where a threat actor records a transmission and replays it later, e.g. to repeat an action.)
A rolling code can be enabled which mitigates replay attacks - each transmission contains a 64 bit value which is guaranteed to monotonically increase, so the consumer will reject any data which contains a rolling code already seen. The rolling code also ensures that the data in every packet is different, which makes brute-force attacks on the encryption much more difficult. This is enabled in the provider configuration and adds minor overhead.
NOTE
The rolling code’s upper 32 bit field is incremented and written to flash once at reboot on the provider node. It’s also incremented and written to flash when the lower 32 bit field overflows, which can only happen after a very long time. The consumer side does not store the d rolling codes in flash.
For further protection a ping-pong (or challenge-response) facility is available, which can be enabled in the
consumer configuration. The consumer periodically generates a 32 bit random number (a nonce aka “Number used Once”)
and broadcasts it as a ping. Any provider receiving this nonce will include it in any future encrypted broadcasts as
pong. The consumer expects to get back its most recently transmitted ping in any packets it receives, and will reject
any that do not contain it.
Use of the ping-pong feature will add to network traffic and the size of the transmitted packets (a single packet may include up to 4 nonces from different devices) but provides a high level of protection against replay attacks. It does require a 2-way network connection, and it only works on local networks because the consumer can only broadcast the nonce to the providers.
In addition when using ping-pong, a connection status binary sensor can be created. The status sensor will report
connected when the consumer has received a pong from the provider within the last ping_pong_recycle_time. If not
received, it will report disconnected. This can be used to detect when a provider is no longer available, or when
the encryption key has changed.
NOTE
Occasionally a Ping key not seen warning message may appear in the device log. This is expected, because it may
happen that while the consumer has regenerated the ping key, it subsequently received a pong with the previous key,
most likely because the messages crossed in transit. In such a case, the message will be rejected, but the next message
will contain the correct pong.
Because of this, ping-pong is only recommended to be used for state transmissions, which are updated periodically
at update_interval.
Security considerations
Section titled “Security considerations”The encryption used is XXTEA which is fast and compact. Although XXTEA is known to be susceptible to a chosen-plaintext attack, such an attack is not possible with this application, and it otherwise has no published weaknesses 1. The implementation used here has been modified slightly to use a 256 bit key which will strengthen security compared to the original 128 bit key.
When encryption is used, all data is encrypted except the sender node name, and the initial request for a ping-pong key. Broadcasting names does not compromise security, since this information would already be available via mDNS. Requesting a key in clear text does not reduce the security of the key, since it is the ability to encrypt this key with the shared secret key that provides the security assurance.
This does mean however that there is a possible Denial of Service attack by a malicious node overwriting a valid ping-pong key, which will result in packets being rejected by the legitimate consumer.
Configuration examples
Section titled “Configuration examples”This example couples two light switches in two different devices, so that switching either one on or off will cause the other to follow suit. In each case a template binary_sensor is used to mirror the switch state.
# Device 1esphome: name: device-1
packet_transport: binary_sensors: - relay1_sensor
switch: - platform: gpio pin: GPIO6 id: relay1 name: "Device 1 switch"
binary_sensor: - platform: template id: relay1_sensor lambda: "return id(relay1).state;"
- platform: packet_transport provider: device-2 id: relay2_sensor on_press: switch.turn_on: relay1 on_release: switch.turn_off: relay1
# Device 2esphome: name: device-2
packet_transport: binary_sensors: - relay2_sensor
switch: - platform: gpio pin: GPIO6 id: relay2 name: "Device 2 switch"
binary_sensor: - platform: template id: relay2_sensor lambda: "return id(relay2).state;"
- platform: packet_transport provider: device-1 id: relay1_sensor on_press: switch.turn_on: relay2 on_release: switch.turn_off: relay2The following example shows a device using encryption to read a sensor and two binary sensors from two different devices, one with encryption and ping-pong and one without. It also rebroadcasts one of those binary sensors with its own encryption and a rolling code to a remote host.
packet_transport: update_interval: 60s ping_pong_enable: true rolling_code_enable: true encryption: "Muddy Waters" binary_sensors: - tick_tock providers: - name: st7735s encryption: "Blind Willie Johnson" # - name: room-lights # Not required here since no encryption
binary_sensor: - platform: packet_transport provider: st7735s id: tick_tock - platform: packet_transport provider: room-lights id: relay1_sensor
sensor: - platform: packet_transport provider: st7735s id: wifi_signal_sensorIn the example below we differentiate channels we establish over UDP, by providing multiple configuration keys.
We provide the value of sensor_to_provide encrypted, to a node with a specific IP address, and we receive the
state of relay1_sensor from tne node named device-1 without any encryption.
udp: - id: udp_output addresses: - 192.168.1.78 # the IP of the specific node to provide the sensor value to - id: udp_input
packet_transport: - platform: udp id: transport_output udp_id: udp_output encryption: !secret your_encryption_key sensors: - sensor_to_provide - platform: udp id: transport_input udp_id: udp_input providers: - name: device-1
sensor: - platform: ... id: sensor_to_provide
binary_sensor: - platform: packet_transport transport_id: transport_input provider: device-1 remote_id: relay1_sensorSee Also
Section titled “See Also”Footnotes
Section titled “Footnotes”-
As known in 2025.02. ↩