From 53807bdbae7c5502af0665f17b211e2ab84cb4d4 Mon Sep 17 00:00:00 2001
From: Aiden
Date: Sat, 3 Oct 2026 18:30:32 +0800
Subject: [PATCH] Add new device
---
athom-usb-switch.yaml | 355 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 355 insertions(+)
create mode 100644 athom-usb-switch.yaml
diff --git a/athom-usb-switch.yaml b/athom-usb-switch.yaml
new file mode 100644
index 0000000..b28c5b5
--- /dev/null
+++ b/athom-usb-switch.yaml
@@ -0,0 +1,355 @@
+substitutions:
+ # Default name
+ name: "athom-usb-switch"
+ # Default friendly name
+ friendly_name: "Athom USB Switch"
+ # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. Typically used for areas such as 'Lounge Room', 'Kitchen' etc
+ room: ""
+ # Description as appears in ESPHome & top of webserver page
+ device_description: "athom esp32-c6 smart usb switch"
+ # Project Name
+ project_name: "China Athom Technology.Athom USB Switch"
+ # Projection version denotes the release version of the yaml file, allowing checking of deployed vs latest version
+ project_version: "v2.0.0"
+ # Restore the relay (GPO switch) upon reboot to state:
+ relay_restore_mode: RESTORE_DEFAULT_ON
+ # Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
+ dns_domain: ".local"
+ # Set timezone of the smart plug. Useful if the plug is in a location different to the HA server. Can be entered in unix Country/Area format (i.e. "Australia/Sydney")
+ timezone: ""
+ # Set the duration between the sntp service polling ntp.org servers for an update
+ sntp_update_interval: 6h
+ # Network time servers for your region, enter from lowest to highest priority. To use local servers update as per zones or countries at: https://www.ntppool.org/zone/@
+ sntp_server_1: "0.pool.ntp.org"
+ sntp_server_2: "1.pool.ntp.org"
+ sntp_server_3: "2.pool.ntp.org"
+ # Enables faster network connections, with last connected SSID being connected to and no full scan for SSID being undertaken
+ wifi_fast_connect: "false"
+ # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
+ log_level: "DEBUG"
+ # Enable or disable the use of IPv6 networking on the device
+ ipv6_enable: "false"
+
+ power_type: "usb"
+########################## End of Substitutions #########################
+
+#############################ESP32C6###########################
+
+ relay_pin: GPIO7
+ button_pin: GPIO15
+ led_pin: GPIO3
+#############################ESP32C6########################
+
+
+esphome:
+ name: "${name}"
+ friendly_name: "${friendly_name}"
+ comment: "${device_description}"
+ area: "${room}"
+ name_add_mac_suffix: true
+ min_version: 2026.8.0
+ project:
+ name: "${project_name}"
+ version: "${project_version}"
+ platformio_options:
+ board_build.mcu: esp32c6
+ board_build.variant: esp32c6
+ board_build.flash_mode: dio
+ on_boot:
+ - priority: 600
+ then:
+ - select.set_index:
+ id: power_mode
+ index: !lambda |-
+ return id(restore_mode)-1;
+ - lambda: |-
+ switch(id(restore_mode))
+ {
+ case 1:{
+ id(relay).turn_off();
+ break;
+ }
+ case 2:{
+ id(relay).turn_on();
+ break;
+ }
+ default:{
+ break;
+ }
+ }
+
+
+esp32:
+ board: esp32-c6-devkitm-1
+ flash_size: 4MB
+ variant: ESP32C6
+ framework:
+ type: esp-idf
+ version: recommended
+ sdkconfig_options:
+ # @grigi found in testing that these options resulted in better responsiveness.
+ # BLE 4.2 is supported by ALL ESP32 boards that have bluetooth, the original and derivatives.
+ CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
+ # Also enable this on any derivative boards (S2, C3 etc) but not the original ESP32.
+ CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
+ # Extend the watchdog timeout, so the device reboots if the device appears locked up for over 10 seconds.
+ CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10"
+
+preferences:
+ flash_write_interval: 5min
+
+api:
+ # reboot_timeout: 0s
+ # Only enable BLE tracking when wifi is up and api is connected
+ # Gives single-core ESP32-C3 devices time to manage wifi and authenticate with api
+ on_client_connected:
+ - esp32_ble_tracker.start_scan:
+ continuous: true
+ # Disable BLE tracking when there are no api connections live
+ on_client_disconnected:
+ if:
+ condition:
+ not:
+ api.connected:
+ then:
+ - esp32_ble_tracker.stop_scan:
+
+ota:
+ - platform: esphome
+ id: ota_esphome
+ # Enables OTA firmware flashing from a URL (used by the update component below)
+ - platform: http_request
+ id: ota_http_request
+
+# Required by the ota http_request platform and the update component.
+# verify_ssl: false skips TLS cert validation to reduce heap/RAM pressure during
+# the download; the manifest's MD5 still verifies firmware integrity before flashing.
+http_request:
+ id: http_request_component
+ verify_ssl: false
+
+update:
+ # Managed updates via HTTP request: periodically checks the published manifest
+ # and exposes a "Firmware Update" entity, pointing at this device's GitHub Pages
+ # manifest. Pages URLs avoid the redirect/buffer issues of Release download URLs.
+ - platform: http_request
+ id: update_http_request
+ name: "Firmware Update"
+ source: https://athom-tech.github.io/esp32-configs/firmware/athom-usb-switch.manifest.json
+ # update_interval defaults to 6h (how often it checks, not installs)
+
+logger:
+ baud_rate: 0 # 0 Enables logging, but disables serial-port logging to free CPU and memory
+ level: ${log_level}
+
+mdns:
+ disabled: false
+
+web_server:
+ port: 80
+
+network:
+ enable_ipv6: ${ipv6_enable}
+
+wifi:
+ # This spawns an AP with the device name and mac address with no password.
+ ap: {}
+ # Allow rapid re-connection to previously connect WiFi SSID, skipping scan of all SSID
+ fast_connect: "${wifi_fast_connect}"
+ # Define dns domain / suffix to add to hostname
+ domain: "${dns_domain}"
+
+captive_portal:
+
+esp32_improv:
+ authorizer: none
+
+esp32_ble_tracker:
+ scan_parameters:
+ # Don't auto start BLE scanning, we control it in the `api` block's automation.
+ continuous: false
+ active: true # send scan-request packets to gather more info, like device name for some devices.
+ interval: 320ms # default 320ms - how long to spend on each advert channel
+ window: 300ms # default 30ms - how long to actually "listen" in each interval. Reduce this if device is unstable.
+ # If the device cannot keep up or becomes unstable, reduce the "window" setting. This may be
+ # required if your device is controlling other sensors or doing PWM for lights etc.
+
+bluetooth_proxy:
+ active: true
+
+dashboard_import:
+ package_import_url: github://athom-tech/esp32-configs/athom-usb-switch.yaml
+
+globals:
+ - id: restore_mode
+ type: int
+ restore_value: yes
+ initial_value: "2" # 0 = Always_Off. 1 = Restore_Power_Off. 2 = Always_On.
+
+select:
+ - platform: template
+ name: "Power On State"
+ id: "power_mode"
+ optimistic: true
+ icon: mdi:electric-switch
+ options:
+ - Always Off
+ - Always On
+ - Restore Power Off State
+ on_value:
+ then:
+ - lambda: |-
+ id(restore_mode)=i+1;
+
+binary_sensor:
+ - platform: status
+ name: "Status"
+ id: id_status
+ icon: mdi:check-network-outline
+ entity_category: diagnostic
+
+ - platform: gpio
+ pin:
+ number: ${button_pin}
+ mode: INPUT_PULLUP
+ inverted: true
+ name: "Power Button"
+ id: power_button
+ disabled_by_default: true
+ filters:
+ - delayed_on_off: 20ms
+ on_multi_click:
+ - timing:
+ - ON for at most 1s
+ - OFF for at least 0.2s
+ then:
+ # Ignore short press when child lock is on, to stop kids toggling the socket
+ - if:
+ condition:
+ switch.is_off: child_lock
+ then:
+ - switch.toggle: relay
+ - timing:
+ - ON for at least 4s
+ then:
+ # Ignore long press when child lock is on, to prevent accidental factory reset
+ - if:
+ condition:
+ switch.is_off: child_lock
+ then:
+ - button.press: Reset
+
+sensor:
+ - platform: uptime
+ name: "Uptime Sensor"
+ id: uptime_sensor
+ type:
+ timestamp
+ entity_category: "diagnostic"
+
+ - platform: wifi_signal
+ name: "WiFi Signal dB"
+ id: wifi_signal_db
+ update_interval: 60s
+ entity_category: "diagnostic"
+
+ - platform: copy
+ source_id: wifi_signal_db
+ name: "WiFi Signal Percent"
+ id: wifi_signal_percent
+ filters:
+ - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
+ unit_of_measurement: "Signal %"
+ entity_category: "diagnostic"
+ device_class: ""
+
+button:
+ - platform: restart
+ name: "Restart"
+ id: id_restart
+ entity_category: config
+
+ - platform: factory_reset
+ name: "Factory Reset"
+ id: Reset
+ entity_category: config
+
+ - platform: safe_mode
+ name: "Safe Mode"
+ id: id_safe_mode
+ internal: false
+ entity_category: config
+
+switch:
+ - platform: gpio
+ name: "Switch"
+ pin: ${relay_pin}
+ id: relay
+ restore_mode: ${relay_restore_mode}
+ icon: mdi:${power_type}
+
+ # Child lock: when on, ignore physical button short/long press, but keep remote (HA/web) control working
+ - platform: template
+ name: "Child Lock"
+ id: child_lock
+ icon: mdi:lock
+ optimistic: true
+ restore_mode: RESTORE_DEFAULT_OFF # Keep last state after power loss/reboot, default off on first boot
+ entity_category: config
+
+light:
+ - platform: status_led
+ name: "Status LED"
+ id: blue_led
+ icon: mdi:lightbulb-outline
+ disabled_by_default: true
+ pin:
+ inverted: true
+ number: ${led_pin}
+
+text_sensor:
+ - platform: wifi_info
+ ip_address:
+ name: "IP Address"
+ icon: mdi:ip-network
+ entity_category: diagnostic
+ ssid:
+ name: "Connected SSID"
+ icon: mdi:wifi-strength-2
+ entity_category: diagnostic
+ mac_address:
+ name: "Mac Address"
+ icon: mdi:network-pos
+ entity_category: diagnostic
+
+ # Creates a sensor showing when the device was last restarted
+ - platform: template
+ name: 'Last Restart'
+ id: device_last_restart
+ icon: mdi:clock
+ entity_category: diagnostic
+# device_class: timestamp
+
+time:
+ - platform: sntp
+ id: sntp_time
+ # Define the timezone of the device
+ timezone: "${timezone}"
+ # Change sync interval from default 5min to 6 hours (or as set in substitutions)
+ update_interval: ${sntp_update_interval}
+ # Set specific sntp servers to use
+ servers:
+ - "${sntp_server_1}"
+ - "${sntp_server_2}"
+ - "${sntp_server_3}"
+ # Publish the time the device was last restarted
+ on_time_sync:
+ then:
+ # Update last restart time, but only once.
+ - if:
+ condition:
+ lambda: 'return id(device_last_restart).state == "";'
+ then:
+ - text_sensor.template.publish:
+ id: device_last_restart
+ state: !lambda 'return id(sntp_time).now().strftime("%a %d %b %Y - %I:%M:%S %p");'