Saving input from mqtt topic to global variable

Hello,
I am trying to save input from an mqtt topic to a global variable, so I can use it later. Unfortunately there seems to be a problem with encoding.
My config.yml looks like this:

esphome:
  name: test

esp8266:
  board: d1_mini

# Enable logging
logger:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Example configuration entry
mqtt:
  broker: !secret mqtt_host
  username: !secret mqtt_user
  password: !secret mqtt_password
  on_json_message:
    topic: test
    then:
      - globals.set:
          id: test_var
          value: !lambda |-
            ESP_LOGD("main", "test_mqtt: %s", x["0"].as<const char*>());
            return x["0"].as<const char*>();

globals:
  - id: test_var
    type: const char*
    restore_value: no
    initial_value: '"Init"'

interval:
  - interval: 1sec
    then:
      - lambda: |-
          ESP_LOGD("main", "test_interval: %s", id(test_var));

I am using docker to compile and upload it.

sudo docker run --rm --privileged -v "${PWD}"/config:/config --device=/dev/ttyUSB0 -it ghcr.io/esphome/esphome run test.yaml

I’ve logged the variables value to debug. Output is:

[12:45:32][D][main:038]: test_interval: Init
[12:45:33][D][main:038]: test_interval: Init
[12:45:33][D][main:025]: test_mqtt: test1234
[12:45:34][D][main:038]: test_interval: 
[12:45:35][D][main:038]: test_interval: 
[12:45:36][D][main:038]: test_interval: 
[12:45:37][D][main:038]: test_interval: 
[12:45:38][D][main:038]: test_interval: 
[12:45:39][D][main:038]: test_interval: 
[12:45:39][D][main:025]: test_mqtt: test1234
[12:45:40][D][main:038]: test_interval: [\xd5\xecKY\xbd\xf2$
[12:45:41][D][main:038]: test_interval: m
[12:45:42][D][main:038]: test_interval: 
[12:45:43][D][main:038]: test_interval: 
[12:45:44][D][main:038]: test_interval: 
[12:45:45][D][main:038]: test_interval: 
[12:45:45][D][main:025]: test_mqtt: test12345
[12:45:46][D][main:038]: test_interval: 
[12:45:47][D][main:038]: test_interval: 

I published multiple test messages to my test topic. You can see the value being properly logged for test_mqtt, but I can’t get the proper value from the var.

Does somebody have an idea about what I am doing wrong? Thanks a lot. Help is highly appreciated.

You’re saving a pointer. Likely, the address is actually saved, but not the C string that is the json message that the address points to.
You’d have to do the equivalent of a strcpy to a global of type char[256], but not clue if it’s possible in an esphome lambda.

Yes, you’re right. Tried strcpy, but it seems not to work due to the different types.

strcpy(test_var, x["0"]);


test.yaml:24:14: error: cannot convert 'esphome::globals::GlobalsComponent<const char*>*' to 'char*'

Made it work

mqtt:
  broker: !secret mqtt_host
  username: !secret mqtt_user
  password: !secret mqtt_password
  on_json_message:
    topic: test
    then:
      - globals.set:
          id: test_var
          value: !lambda |-
            ESP_LOGD("main", "test_mqtt: %s", x["0"].as<const char*>());
            char* test_tmp = "";
            strcpy(test_tmp, x["0"]);
            return test_tmp;

Output:

[14:25:43][D][main:040]: test_interval: Init
[14:25:44][D][main:040]: test_interval: Init
[14:25:44][D][main:025]: test_mqtt: test12345
[14:25:45][D][main:040]: test_interval: test12345
[14:25:46][D][main:040]: test_interval: test12345
[14:25:47][D][main:040]: test_interval: test12345

Not beautiful, but it does the job. If somebody has a nice solution other than using a temp var, I’d be happy. :slight_smile:

Mmm… Not sure if it’s an esphome thing, but that’s not supposed to work properly.
You are effectively creating a single char reserved memory, here, so any strcpy of more than 1 char is (potentially) overwriting something else it doesn’t own.

As I said before, try, e.g. char[256] = "";, where 256 is the max theoretical size of the variable.

Problem is, I want to feed it to a lcd display, later. That requires char*

src/esphome/components/globals/globals_component.h:15:68: error: incompatible types in assignment of 'char*' to 'char [256]'

Well, purely C++ speaking, a char[] is a char*. Might be an esphome issue…
You might try through a std::string and get a char* through c_str()