substitutions: name: "owon-b35t" friendly_name: "OWON B35T Multimeter" device_description: "M5Stack Core 1 BLE client for OWON B35T/B35T+ multimeter with local graphical display" owon_mac_address: !secret owon_b35t_mac_address esphome: name: ${name} friendly_name: ${friendly_name} comment: ${device_description} min_version: 2024.6.0 includes: - owon_b35t.h project: name: "custom.owon-b35t-m5stack" version: "1.0" esp32: board: m5stack-core-esp32 framework: type: esp-idf advanced: minimum_chip_revision: "3.1" logger: level: INFO api: encryption: key: !secret apikey ota: platform: esphome password: !secret ota wifi: ssid: "Voltage-legacy" password: !secret voltage_legacy_psk #use_address: ${name}.home power_save_mode: none fast_connect: on min_auth_mode: WPA2 ap: ssid: "OWON B35T Fallback Hotspot" password: !secret fallback_psk captive_portal: esp32_ble_tracker: scan_parameters: active: true ble_client: - mac_address: ${owon_mac_address} id: owon_ble_client on_connect: then: - lambda: |- owon_meter.on_connect(); on_disconnect: then: - lambda: |- owon_meter.on_disconnect(); spi: clk_pin: GPIO18 mosi_pin: GPIO23 miso_pin: GPIO19 output: - platform: ledc pin: GPIO32 id: lcd_backlight light: - platform: monochromatic output: lcd_backlight name: "${friendly_name} Backlight" id: backlight restore_mode: ALWAYS_ON font: - file: "fonts/Roboto-Regular.ttf" id: meter_font size: 15 glyphs: [ " ", "!", "%", "+", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "<", ">", "A", "B", "C", "D", "E", "F", "G", "H", "I", "L", "M", "N", "O", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "c", "d", "e", "f", "g", "i", "k", "m", "n", "o", "r", "s", "t", "u", "v", "w", "y", "z", "°", "µ", "Ω", ] display: - platform: ili9xxx id: lcd model: M5STACK cs_pin: GPIO14 dc_pin: GPIO27 reset_pin: GPIO33 invert_colors: false color_palette: 8BIT rotation: 0 update_interval: 500ms lambda: |- owon_meter.render(it, id(meter_font)); binary_sensor: - platform: gpio id: button_a pin: number: GPIO39 inverted: true internal: true on_press: then: - lambda: |- owon_meter.previous_button(); - platform: gpio id: button_b pin: number: GPIO38 inverted: true internal: true on_click: - min_length: 50ms max_length: 1500ms then: - logger.log: level: INFO format: "OWON short press: %s" args: ["owon_meter.selected_button_name()"] - ble_client.ble_write: id: owon_ble_client service_uuid: "0000fff0-0000-1000-8000-00805f9b34fb" characteristic_uuid: "0000fff3-0000-1000-8000-00805f9b34fb" value: !lambda |- std::vector data = {owon_meter.selected_button, 0x01}; return data; - min_length: 1500ms max_length: 5000ms then: - logger.log: level: INFO format: "OWON long press: %s" args: ["owon_meter.selected_button_name()"] - ble_client.ble_write: id: owon_ble_client service_uuid: "0000fff0-0000-1000-8000-00805f9b34fb" characteristic_uuid: "0000fff3-0000-1000-8000-00805f9b34fb" value: !lambda |- uint8_t press_type = (owon_meter.selected_button == 1 || owon_meter.selected_button == 5) ? 0x01 : 0x00; std::vector data = {owon_meter.selected_button, press_type}; return data; - platform: gpio id: button_c pin: number: GPIO37 inverted: true internal: true on_press: then: - lambda: |- owon_meter.next_button(); - platform: template name: "${friendly_name} Connected" lambda: |- return owon_meter.connected; - platform: template name: "${friendly_name} Overload" lambda: |- return owon_meter.overload; - platform: template name: "${friendly_name} Low Battery" lambda: |- return owon_meter.low_battery; - platform: template name: "${friendly_name} Auto Range" lambda: |- return owon_meter.auto_range(); - platform: template name: "${friendly_name} Hold" lambda: |- return owon_meter.hold(); - platform: template name: "${friendly_name} Relative" lambda: |- return owon_meter.relative(); - platform: template name: "${friendly_name} AC" lambda: |- return owon_meter.ac(); - platform: template name: "${friendly_name} DC" lambda: |- return owon_meter.dc(); - platform: template name: "${friendly_name} Continuity" lambda: |- return owon_meter.continuity(); - platform: template name: "${friendly_name} Diode" lambda: |- return owon_meter.diode(); sensor: - platform: ble_client type: characteristic ble_client_id: owon_ble_client id: owon_notify_source internal: true service_uuid: "0000fff0-0000-1000-8000-00805f9b34fb" characteristic_uuid: "0000fff4-0000-1000-8000-00805f9b34fb" notify: true update_interval: never lambda: |- owon_meter.handle_notify(x); return owon_meter.value(); - platform: wifi_signal name: "${friendly_name} WiFi Signal" update_interval: 60s - platform: template name: "${friendly_name} Display Value" id: owon_display_value accuracy_decimals: 6 update_interval: 1s lambda: |- return owon_meter.has_reading && !owon_meter.overload ? owon_meter.value() : NAN; - platform: template name: "${friendly_name} Base Value" id: owon_base_value accuracy_decimals: 9 update_interval: 1s lambda: |- return owon_meter.has_reading && !owon_meter.overload ? owon_meter.value_base() : NAN; - platform: template name: "${friendly_name} Voltage" device_class: voltage unit_of_measurement: "V" accuracy_decimals: 6 update_interval: 1s lambda: |- return owon_meter.kind() == owon_b35t::Meter::KIND_VOLTAGE && !owon_meter.overload ? owon_meter.value_base() : NAN; - platform: template name: "${friendly_name} Current" device_class: current unit_of_measurement: "A" accuracy_decimals: 6 update_interval: 1s lambda: |- return owon_meter.kind() == owon_b35t::Meter::KIND_CURRENT && !owon_meter.overload ? owon_meter.value_base() : NAN; - platform: template name: "${friendly_name} Resistance" unit_of_measurement: "Ω" accuracy_decimals: 3 update_interval: 1s lambda: |- return owon_meter.kind() == owon_b35t::Meter::KIND_RESISTANCE && !owon_meter.overload ? owon_meter.value_base() : NAN; - platform: template name: "${friendly_name} Frequency" device_class: frequency unit_of_measurement: "Hz" accuracy_decimals: 3 update_interval: 1s lambda: |- return owon_meter.kind() == owon_b35t::Meter::KIND_FREQUENCY && !owon_meter.overload ? owon_meter.value_base() : NAN; - platform: template name: "${friendly_name} Capacitance" unit_of_measurement: "F" accuracy_decimals: 12 update_interval: 1s lambda: |- return owon_meter.kind() == owon_b35t::Meter::KIND_CAPACITANCE && !owon_meter.overload ? owon_meter.value_base() : NAN; - platform: template name: "${friendly_name} Temperature" device_class: temperature unit_of_measurement: "°C" accuracy_decimals: 2 update_interval: 1s lambda: |- if (owon_meter.kind() == owon_b35t::Meter::KIND_TEMP_C && !owon_meter.overload) return owon_meter.value(); if (owon_meter.kind() == owon_b35t::Meter::KIND_TEMP_F && !owon_meter.overload) return (owon_meter.value() - 32.0f) * 5.0f / 9.0f; return NAN; - platform: template name: "${friendly_name} Duty Cycle" unit_of_measurement: "%" accuracy_decimals: 2 update_interval: 1s lambda: |- return owon_meter.kind() == owon_b35t::Meter::KIND_DUTY && !owon_meter.overload ? owon_meter.value() : NAN; text_sensor: - platform: template name: "${friendly_name} Reading" update_interval: 1s lambda: |- return owon_meter.reading_text(); - platform: template name: "${friendly_name} Unit" update_interval: 1s lambda: |- return std::string(owon_meter.scale()) + owon_meter.unit(); - platform: template name: "${friendly_name} Mode" update_interval: 1s lambda: |- return owon_meter.mode_text(); - platform: template name: "${friendly_name} Meter Type" update_interval: 1s lambda: |- return owon_meter.is_plus ? std::string("B35T+") : std::string("B35T"); - platform: template name: "${friendly_name} Selected Button" update_interval: 1s lambda: |- return std::string(owon_meter.selected_button_name());