Weber Connect Smart Grilling Hub integration

here’s a sample template I feed into the main yaml…

############################################
# MODULE: iGrill 3 BLE Integration Template
# TYPE: Sensor + BLE Client
# CREATED: 2025-10-06
# AUTHOR: Soup (Steve Campbell)
#
# INPUTS:
#   - MAC address (BLE)
#   - Battery level (AA or docked)
#   - Propane level (if docked)
#   - Temperature probes 1–4
#
# OUTPUTS:
#   - Connection status (binary + text)
#   - Battery sensor (template)
#   - Propane status (emoji + %)
#   - Probe temps (raw + emoji summary)
#
# RUNTIME IMPACT:
#   - BLE scan + 60s polling
#   - 4 probe sensors + propane + battery
############################################

ble_client:
  - mac_address: ${mac_address}
    id: ${igrill_id}
    on_connect:
      then:
        - binary_sensor.template.publish:
            id: ${igrill_id}_connection
            state: ON
    on_disconnect:
      then:
        - binary_sensor.template.publish:
            id: ${igrill_id}_connection
            state: OFF

binary_sensor:
  - platform: template
    name: "${igrill_name} Connection"
    id: ${igrill_id}_connection
    device_class: connectivity

sensor:
  - platform: igrill
    ble_client_id: ${igrill_id}
    update_interval: 60s
    send_value_when_unplugged: true
    unplugged_probe_value: 0
    battery_level:
      name: "${igrill_name} Battery"
      id: ${igrill_id}_battery
    propane_level:
      name: "${igrill_name} Propane"
      id: ${igrill_id}_propane
    temperature_probe1:
      name: "${igrill_name} Probe 1"
      id: ${igrill_id}_probe1
    temperature_probe2:
      name: "${igrill_name} Probe 2"
      id: ${igrill_id}_probe2
    temperature_probe3:
      name: "${igrill_name} Probe 3"
      id: ${igrill_id}_probe3
    temperature_probe4:
      name: "${igrill_name} Probe 4"
      id: ${igrill_id}_probe4

text_sensor:
  - platform: template
    name: "${igrill_name} MAC Address"
    id: ${igrill_id}_mac
    lambda: |-
      return std::string("${mac_address}");


  - platform: template
    name: "${igrill_name} Probe Summary"
    id: ${igrill_id}_summary
    lambda: |-
      if (!id(${igrill_id}_connection).state) {
        return {"🔌 OFFLINE"};
      }
      auto format_probe = [](float temp) -> std::string {
        if (temp <= 0.0) return "🧊";
        if (temp < 100.0) return "🌡️ " + to_string((int)temp) + "°F";
        return "🔥 " + to_string((int)temp) + "°F";
      };
      std::string p1 = format_probe(id(${igrill_id}_probe1).state);
      std::string p2 = format_probe(id(${igrill_id}_probe2).state);
      std::string p3 = format_probe(id(${igrill_id}_probe3).state);
      std::string p4 = format_probe(id(${igrill_id}_probe4).state);
      return "P1: " + p1 + " | P2: " + p2 + " | P3: " + p3 + " | P4: " + p4;



  

and the “main” (at least as I see it)

############################################
# MODULE: BLE iGrill Monitor (Mini + iGrill 3 x2)
# TYPE: ESPHome Config + Substitutions
# CREATED: 2025-10-06
# AUTHOR: Soup (Steve Campbell)
#
# INCLUDES:
#   - soup_device_base.yaml (shared device config)
#   - template_igrill_mini.yaml (Mini logic)
#   - template_igrill_3.yaml (iGrill 3 logic)
#
# UNITS:
#   - iGrill Mini DE9B (mac_address_1)
#   - iGrill 3 9999 (mac_address_2)
#   - iGrill 3 5843 (mac_address_3)
#
# ENTITY ID FORMAT:
#   - All IDs use last 4 of MAC for uniqueness
#   - Example: igrill_mini_de9b_connection_bin
#
# RUNTIME IMPACT:
#   - BLE scan + 60s polling per unit
#   - Avoid MAC collisions or scan overlap
#
# FUTURE:
#   - Add alert logic for propane + probe temps
#   - Expand overlay tile with grill mode + vibe
#  mac_address_1: "70:91:8F:98:DE:9B"
#  mac_address_2: "70:91:8F:98:1C:9B"
#  mac_address_3: "70:91:8F:1E:58:43"  #New Igrill3
############################################

substitutions:
  name: esphome-web-7a0558
  friendly_name: BLE iGrill 7A0558 Modular

  igrill_mini_mac: "70:91:8F:98:DE:9B"
  igrill_mini_name: "iGrill Mini DE9B"
  igrill_mini_id: "igrill_mini_de9b"

  # iGrill 3 1C9B (old)
  igrill_3_1C9B_mac: "70:91:8F:06:1C:9B"
  igrill_3_1C9B_name: "iGrill 3 1C9B"
  igrill_3_1C9B_id: "igrill_3_1c9b"

  # iGrill 3 5843 (new)
  igrill_3_5843_mac: "70:91:8F:1E:58:43"
  igrill_3_5843_name: "iGrill 3 5843"
  igrill_3_5843_id: "igrill_3_5843"

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  name_add_mac_suffix: false
  project:
    name: esphome.web
    version: '1.0'

esp32:
  board: esp32dev
  framework:
    type: esp-idf

web_server:

esp32_ble_tracker:
  scan_parameters:
    window: 160ms
    interval: 160ms

external_components:
  - source: github://bendikwa/[email protected]

packages:
  device_base: !include 
    file: soup_device_base.yaml

  igrill_mini: !include 
    file: igrill_mini_template.yaml
    vars:
      mac_address: ${igrill_mini_mac}
      igrill_name: ${igrill_mini_name}
      igrill_id: ${igrill_mini_id}

  igrill_3_1D9B: !include
    file: igrill_3_template.yaml
    vars:
      mac_address: ${igrill_3_1C9B_mac}
      igrill_name: ${igrill_3_1C9B_name}
      igrill_id: ${igrill_3_1C9B_id}

  igrill_3_5843: !include
    file: igrill_3_template.yaml
    vars:
      mac_address: ${igrill_3_5843_mac}
      igrill_name: ${igrill_3_5843_name}
      igrill_id: ${igrill_3_5843_id}