KNX to TCP-IP communication

Hello,

I would like to establish communication between a KNX installation and an ESP8266. When a KNX button is pressed, a data packet is to be sent to the ESP8266 via WLAN, the response data packet is to be evaluated and a response sent to the button. I have an automation that is triggered via KNX and sends a data packet to the ESP8266 via a shell command. The ESP then sends back 5 bytes. This works well. The shell command looks like this:

shell_command:
  # Send data to the ESP8266
  fireplace_on: echo -ne "\x01\x02\x03" | nc 192.168.178.111 80

First of all, I would like to know where I can find the documentation? What does -ne or | nc make? Next, I would like to know how I can select a specific byte from the received data (5 bytes) and send it back via KNX. I have implemented the expose function for this, but it doesn’t work.

alias: KNX ESP8266 Test
description: ""
trigger:
  - platform: event
    event_type: knx_event
    event_data:
      destination: 6/0/1
condition: []
action:
  - service: shell_command.fireplace_on
    data: {}
    response_variable: return_response
    # How to evaluate the data? How can I send e. g. the second byte back to KNX?
mode: single

Hi :wave:!

Find the documentation for nc here https://linux.die.net/man/1/nc

Hey guys,

i am now able to receive the data from the ESP and send it back to KNX. However, most of the time the received data from the ESP via the shell command is empty. The displayed text is then:

{‘stdout’: ", ‘stderr’: ‘’, ‘returncode’: 0}

Only every 10th to 20th attempt returns data. I was able to ensure that the problem is not in the ESP itself, which answers every request from the shell command. Here is my shell command (located in configuration.yaml):

shell_command:
  # Command to send and receive data from an ESP8266 
  read_esp8266: echo -ne '\x01\x02\x03' | nc 192.168.178.111 80

And here is the code of my automation:

alias: Automatisierung1
description: ""
trigger:
  - platform: event
    event_type: knx_event # Trigger automation by KNX telegram 
    event_data:
      destination: 6/0/1
condition: []
action:
  - service: shell_command.read_esp8266 # Send a command to the ESP8266
    data: {}
    response_variable: return_response # Read out the answere package from the ESP8266

  - service: input_text.set_value # Display the received value on dash board to check the communication
    data:
      value: '{{ return_response }}'
    target:
      entity_id: input_text.text1

  - service: knx.send
    data:
      address: 6/0/2
      payload: '{{ return_response.stdout[1] | ord }}' # Send the recieved value (0 or 1) back to KNX
mode: single

Does anyone have any idea why I am suffering from so many packet losses?

Got it! Actually the problem was related to the ESP8266. Here are my full code examples.

First we need a KNX group address as a trigger source for the automation (located in file knx.yaml or can also be stored in configuration.yaml):

event:
  - address:
      - "6/0/1"

Next the automation code:

alias: Automation1
description: "Kommunication: KNX > HA > ESP8266 > HA > KNX"
trigger:
  - platform: event
    event_type: knx_event
    event_data:
      # Group address, which data is send to ESP8266 (KNX button)
      destination: 6/0/1
condition: []
action:
  - service: shell_command.tcp_esp8266
    data_template:
      # Extract data from KNX button and send it via shell command
      # Important: Use double slash and NO QUOTES!
      # Also Important: Format to hex-code with two digits ('%02x')
      payload: \\x{{ '%02x' % trigger.event.data.data }}\\x00\\x00
    response_variable: return_response
  - service: knx.send
    data:
      address: 6/0/2
      # Return ESP8266's answere to the KNX-Button (state for its switching value)
      payload: "{{ return_response.stdout[0] | ord }}"
mode: single

Due to the fact that it seems to be impossible to send proper parameters to a shell command, i used a bash script. It is namend send_payload.sh and is located in /config:

# Important: Use double quotes around $1 !!!
# $1 is the parameter from the automation
echo -ne "$1" | nc -w 2 192.168.178.111 80

Next, we have to enable the bash script. This is done by entering in to the terminal the following:

chmod +x /config/send_payload.sh

Then we need the shell command (also located in /config):

shell_command:
  # Note: No quotes at all
  tcp_esp8266: bash /config/send_payload.sh {{ payload }}

Finally, we have the following code for the ESP8266:

#include <ESP8266WiFi.h>

// Server-Object for client communication
WiFiServer server(80);

// WLAN access
const char* ssid     = "WLAN_SSID";
const char* password = "TheQueenIsDead";

char inputBuffer[10];
uint8_t counter = 0;

void setup() 
{
  // ON-Board LED for status indication
  pinMode(D0, OUTPUT);

  // Init UART for debugging
  Serial.begin(115200);
  // New line to remove rubbish to the top
  Serial.println("");

  // Start WLAN connection
  Serial.println("Connection to WLAN");
  WiFi.begin(ssid, password);
  // Wait until connection is finish
  while (WiFi.status() != WL_CONNECTED) 
  {
    digitalWrite(D0, HIGH);
    delay(100);
    digitalWrite(D0, LOW);
    delay(100);
    Serial.print(".");
  }
  // Display WLAN data
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // Start server
  server.begin();
  // Switch on LED (inverse logic)
  digitalWrite(D0, LOW);
}

void loop() 
{
  // Listen for incoming clients
  WiFiClient client = server.available();

  if (client) 
  {
    if (client.connected()) 
    {
      // Wait for complete data package (3 bytes)
      while (client.available() < 3);
      // Read received data
      uint8_t receivedData[10];
      uint8_t index = 0;
      while (client.available())
      {
        receivedData[index] = client.read();
        // Display received data
        Serial.println(receivedData[index]);
        index++;
      }
      // Switch LED regarding to the received data
      if (receivedData[0] == 1)
      {
        // LED on (inverse logic!)
        digitalWrite(D0, LOW);
      }
      else
      {
        // LED off
        digitalWrite(D0, HIGH);
      }
      Serial.println("");
      // Send response (state of LED and dummy data)
      uint8_t dataOut[] = {!digitalRead(D0), 0x00, 0x00};
      client.write(dataOut, 3);
    }

    // close the connection:
    client.stop();
  }

}

Maybe someone find this helpfull :slight_smile: