Fabian-Schmidt / esphome-victron_ble

Use official Victron BLE endpoint for fetching data from Victron devices via Bluetooth LE via ESPHome.
GNU General Public License v3.0
152 stars 15 forks source link

Creating template sensor from the sensors #15

Closed adrusa closed 1 year ago

adrusa commented 1 year ago

I was trying to make a template sensor out of some of the sensors here. While it is possible for me to use filters and lambda to return the desired value, that means I will lose the raw data generated by the sensor. The help I need is to create a template sensor out of one of the sensors, but return both the raw data and the templated sensor for use in home assistance. Any help is welcome. I recognised I can do this easily in HA, but I don't want to add additional template to HA. Thank you.

strom-peter commented 1 year ago

@adrusa Hello, I want to use sensor values in .yaml to sent over UDP direct to a server. UDP sending is working, bud how to access the sensor values? maybe you can help me

Fabian-Schmidt commented 1 year ago

Hi,

I am unsure about both questions. Accessing sensor data in lambda can be very easy. Example:

sensor:
# Raw sensor
  - platform: victron_ble
    victron_ble_id: MySmartShunt
    name: "Battery voltage"
    type: BATTERY_VOLTAGE
    id: shunt_BATTERY_VOLTAGE
# Template sensor
  - platform: template
    name: "Template Sensor"
    lambda: |-
      return id(shunt_BATTERY_VOLTAGE).state;
    update_interval: 60s

Maybe @adrusa and @strom-peter can provide an example yaml of the problem?

strom-peter commented 1 year ago

Hello, and thanks for the input, bud i don't know how to start the UDP-script from sensors.... with the button, sending is working


script:
- id: send_udp
  parameters:
    val: float
  then:
    - lambda: |-

          int port = 5000;
          std::string host = "192.168.178.48";
          std::string msg = "measurement ";
          msg.append("tag=");
          msg.append(to_string(val));
          ESP_LOGI("send_udp", "msg= %s", msg.c_str());

          int sock = ::socket(AF_INET, SOCK_DGRAM, 0);
          struct sockaddr_in destination, source;

          destination.sin_family = AF_INET;
          destination.sin_port = htons(port);
          destination.sin_addr.s_addr = inet_addr(host.c_str());

          int n_bytes = ::sendto(sock, msg.c_str(), msg.length(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
          ESP_LOGD("lambda", "Sent %s to %s:%d in %d bytes", msg.c_str(), host.c_str(), port, n_bytes);
          ::close(sock);

# for testing UDP
button:
- platform: template
  id: button_udp_sender
  name: "Send UDP Command"
  on_press:
    - script.execute:
        id: send_udp
        val: 123.45

esp32_ble_tracker:

victron_ble:
  - id: MySmartShunt
    mac_address: ${smart_shunt_mac_address}
    bindkey: ${smart_shunt_encryption_key}
    on_battery_monitor_message:
      - logger.log: "Message from Battery Monitor."

# do I need globals??
globals:
  - id: battU
    type: float

sensor:
# Raw sensor
  - platform: victron_ble
    victron_ble_id: MySmartShunt
    name: "Battery voltage"
    type: BATTERY_VOLTAGE
    id: shunt_BATTERY_VOLTAGE

# Template sensor
  - platform: template
    name: "Template Sensor"
    lambda: |-
        ESP_LOGI("Template sensor", "Value: %f", id(shunt_BATTERY_VOLTAGE).state);
// send to UDP ????
        return id(shunt_BATTERY_VOLTAGE).state;
    update_interval: 10s
Fabian-Schmidt commented 1 year ago

Hi @strom-peter,

I can suggest four possible solutions:

  1. Use on_battery_monitor_message and script.execute:

    victron_ble:
     - id: MySmartShunt
       mac_address: ${smart_shunt_mac_address}
       bindkey: ${smart_shunt_encryption_key}
       on_battery_monitor_message:
         - script.execute:
             id: send_udp
             # 0.01 V to 1 V
             val: !lambda return 0.01f * message->battery_voltage;
  2. Use on_battery_monitor_message and lambda:

    victron_ble:
      - id: MySmartShunt
        mac_address: ${smart_shunt_mac_address}
        bindkey: ${smart_shunt_encryption_key}
        on_battery_monitor_message:
          - lambda: id(send_udp)->execute(0.01f * message->battery_voltage);
  3. Use sensor and script.execute:

    sensor:
      - platform: victron_ble
        victron_ble_id: MySmartShunt
        name: "Battery voltage"
        type: BATTERY_VOLTAGE
        id: shunt_BATTERY_VOLTAGE
        on_value:
          then:
            - script.execute:
                id: send_udp
                val: !lambda return x;
  4. Interval every 10 second just sent the last known value.

    interval:
      - interval: 10s
        then: 
          lambda: |-
            if(!std::isnan(id(shunt_BATTERY_VOLTAGE).state)) {
              id(send_udp)->execute(id(shunt_BATTERY_VOLTAGE).state);
            }

Solution 1-3 generates an UDP package as soon as a new value is received via Bluetooth. So very often. Using on_battery_monitor_message has advantages if you don't need the sensor component and your device has performance or memory consumption issues. Using the sensor is cleaner implementation. Solution 4 is a bit dumb and will also generate values if no new values are found by the Sensor, but it will not generate too many UDP packages.

I am unsure about your use case so I am hoping one of the solutions is suited.

strom-peter commented 1 year ago

@Fabian-Schmidt, many thanks, for fast and competent replay,

I want to readout 4 mppt-charger and send data to influxdb over UDP to visualization data in Grafana. With your help, now 2 chargers works, the other 2 I have to wire up..... I use: on_battery_monitor_message and lambda

victron_ble:
  - id: mppt01
    submit_sensor_data_asap: true
    mac_address: ${mppt01_mac_address}
    bindkey: ${mppt01_encryption_key}
    on_solar_charger_message:
      - lambda: |-
            id(send_udp)->execute("mppt01_battU", 0.01f * message->battery_voltage);
            id(send_udp)->execute("mppt01_battI", 0.1f * message->battery_current);
            id(send_udp)->execute("mppt01_pvPower", message->pv_power);
            id(send_udp)->execute("mppt01_yieldToday", 0.01f * message->yield_today);

  - id: mppt02
    submit_sensor_data_asap: true
    mac_address: ${mppt02_mac_address}
    bindkey: ${mppt02_encryption_key}
    on_solar_charger_message:
      - lambda: |-
            id(send_udp)->execute("mppt02_battU", 0.01f * message->battery_voltage);
            id(send_udp)->execute("mppt02_battI", 0.1f * message->battery_current);
            id(send_udp)->execute("mppt02_pvPower", message->pv_power);
            id(send_udp)->execute("mppt02_yieldToday", 0.01f * message->yield_today);
Fabian-Schmidt commented 1 year ago

@adrusa Can you please share an example configuration so I can assist you?