{"id":50017446,"url":"https://github.com/dallanwagz/j7c_ha","last_synced_at":"2026-06-15T08:01:27.545Z","repository":{"id":358827240,"uuid":"1243180746","full_name":"dallanwagz/j7c_ha","owner":"dallanwagz","description":"Home Assistant custom integration for Atorch BLE USB power meters (J7-C)","archived":false,"fork":false,"pushed_at":"2026-06-15T03:54:16.000Z","size":226,"stargazers_count":0,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T05:17:28.996Z","etag":null,"topics":["atorch","bluetooth","bluetooth-low-energy","hacs","hacs-integration","home-assistant","homeassistant","homeassistant-integration","j7-c","usb-power-meter"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dallanwagz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-19T05:51:47.000Z","updated_at":"2026-06-15T03:54:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dallanwagz/j7c_ha","commit_stats":null,"previous_names":["dallanwagz/j7c_ha"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/dallanwagz/j7c_ha","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallanwagz%2Fj7c_ha","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallanwagz%2Fj7c_ha/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallanwagz%2Fj7c_ha/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallanwagz%2Fj7c_ha/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dallanwagz","download_url":"https://codeload.github.com/dallanwagz/j7c_ha/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dallanwagz%2Fj7c_ha/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34353193,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atorch","bluetooth","bluetooth-low-energy","hacs","hacs-integration","home-assistant","homeassistant","homeassistant-integration","j7-c","usb-power-meter"],"created_at":"2026-05-20T05:00:49.090Z","updated_at":"2026-06-15T08:01:27.536Z","avatar_url":"https://github.com/dallanwagz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Atorch BLE (J7-C) — Home Assistant custom integration\n\n[![HACS Custom](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://hacs.xyz/)\n[![Quality Scale: Gold](https://img.shields.io/badge/quality--scale-gold-yellow.svg)](https://developers.home-assistant.io/docs/core/integration-quality-scale/)\n[![Tests](https://github.com/dallanwagz/j7c_ha/actions/workflows/validate.yml/badge.svg)](https://github.com/dallanwagz/j7c_ha/actions/workflows/validate.yml)\n\nThis integration turns an **Atorch J7-C USB power meter** into a first-class Home Assistant device over Bluetooth Low Energy — no cloud, no manual MAC entry. Voltage, current, power, energy (Wh), capacity (mAh), USB D+/D- voltages, temperature, and runtime are exposed as native HA sensors. The integration treats local Bluetooth adapters and ESPHome Bluetooth proxies identically and works with both.\n\n## Supported devices\n\n| Model | Packet type | Status |\n|-------|-------------|--------|\n| J7-C  | 0x03        | Supported |\n| UC96 (bare module) | 0x03 (same as J7-C) | Should work |\n| DL24, UD18, AC meters | 0x01, 0x02 | Detected but not supported; will surface a repair issue |\n\n## ESPHome Bluetooth proxy basics\n\nESPHome [Bluetooth proxies](https://esphome.io/components/bluetooth_proxy.html) are inexpensive ESP32 nodes that forward BLE advertisements and active connections to Home Assistant, extending Bluetooth coverage beyond the host's radio. **Proxies are optional** — this integration works equally well with a local Bluetooth adapter on the HA host. From the integration's perspective the two are identical: discovery, connection, and notification handling go through the same Home Assistant `bluetooth` stack regardless of which transport carries the packets.\n\n## Hardware setup\n\n1. **Power the Atorch J7-C USB power meter.** Plug it into any USB-A or USB-C source (the meter is USB-bus-powered) and confirm the display is on.\n2. **Place the meter within BLE range** of either:\n   - A **local Bluetooth adapter** on the Home Assistant host (built-in radio or a USB BT dongle recognized by HA's Bluetooth integration), or\n   - An **ESPHome Bluetooth proxy** that already appears under **Settings → Devices \u0026 Services → ESPHome**.\n3. **Wake the meter** by tapping its physical button if the screen is asleep — some firmware variants only advertise while the display is active.\n4. **No pairing PIN is required.** The J7-C advertises as `UC96_BLE` and does not require bonding.\n\n## Installation (via HACS)\n\nUntil this integration is accepted into the HACS default integrations list, install it as a **custom repository**:\n\n1. In Home Assistant, open **HACS → Integrations**.\n2. Click the three-dot menu → **Custom repositories**.\n3. Add `https://github.com/dallanwagz/j7c_ha` with category **Integration**.\n4. Find **Atorch BLE (J7-C)** in the HACS integrations list and click **Download**.\n5. Restart Home Assistant.\n6. Go to **Settings → Devices \u0026 Services**. The Atorch J7-C USB power meter should appear as a discovered device — click **Configure** and confirm.\n\n## Configuration\n\nThe integration uses Bluetooth discovery — **no manual MAC entry**. When the meter is in range it is auto-discovered and presented in **Settings → Devices \u0026 Services** with a confirm step. Submitting the form creates one config entry per meter.\n\n### Options flow\n\nEach config entry has its own options (gear icon on the entry):\n\n- **`connection_mode`**: `persistent` or `polled` (enum).\n- **`poll_interval_seconds`**: integer 10–3600. Only applies in polled mode.\n\nSwitching `connection_mode` applies live — no restart needed.\n\n### Choosing a connection mode\n\n| Mode | Latency | Slot usage | When to choose |\n|------|---------|------------|----------------|\n| **Persistent** | ~1 Hz updates | Holds **one ESPHome-proxy connection slot continuously per meter** | Slot budget allows; you want fast updates |\n| **Polled** | One frame approximately every `poll_interval_seconds` (10–3600 s), on the next advertisement after the interval elapses | Briefly occupies a slot per poll, otherwise idle | Proxy slots are scarce; multiple meters share one proxy |\n\n**Slot-arithmetic rule of thumb:** A typical ESP32 ESPHome BT proxy supports about **3 simultaneous BLE connections**. If you have more meters than the proxy has slots minus one (reserve at least one slot for other BLE devices), choose **Polled** mode for at least the extras. In formula terms, recommend polled when `N_meters \u003e slots - 1`.\n\n**Mode change confirmation:** Switching `connection_mode` via the options flow applies live; sensors may briefly show `Unknown` during the transition while the new mode's first frame is acquired. This is expected behavior, not a fault.\n\n## Sensors exposed\n\nThe integration exposes 10 entities per meter. \"Default enabled\" entities are visible immediately; \"Default disabled\" entities can be enabled per device from the entity registry.\n\n| Entity | Device class | State class | Unit | Default enabled | Notes |\n|--------|--------------|-------------|------|-----------------|-------|\n| Voltage | `voltage` | `measurement` | V | Yes | Bus voltage at the USB port |\n| Current | `current` | `measurement` | A | Yes | Bus current |\n| Power | `power` | `measurement` | W | Yes | Computed (V × A) by the meter |\n| Energy | `energy` | `total_increasing` | Wh | Yes | **Device-side cumulative counter. Cannot be reset over BLE** — reset requires the meter's physical button. Not eligible for the Energy Dashboard because non-monotonic counter resets cannot be guaranteed. |\n| Capacity | `None` (HA Core's `UnitOfElectricCharge` lacks mAh) | `total_increasing` | mAh | Yes | **Device-side cumulative counter. Cannot be reset over BLE** — reset requires the meter's physical button. |\n| Temperature | `temperature` | `measurement` | °C | Yes | Internal sensor on the meter |\n| Runtime duration | `duration` | `total_increasing` | s | Yes | Seconds since last reset on the device |\n| D+ voltage | `voltage` | `measurement` | V | No (advanced) | USB data-plus line voltage |\n| D- voltage | `voltage` | `measurement` | V | No (advanced) | USB data-minus line voltage |\n| Connection state | `enum` | — | — | No (diagnostic) | One of `connected`, `polling`, `disconnected`, `reconnecting`, `failed_after_setup`. Useful for automations that react to integration health. |\n\n## First install — what to expect\n\nAfter confirming the device, sensors may show 'Unknown' until the first measurement arrives — about 1s in persistent mode, and approximately one poll interval (10–3600s) in polled mode, where each poll fires on the next advertisement after the interval elapses. If they remain Unknown for several minutes, see Troubleshooting.\n\nSensors will show **Unknown** or **Unavailable** until the first measurement arrives — typically \u003c5 seconds in persistent mode, up to your configured poll interval in polled mode.\n\nIf sensors remain Unknown for more than a few seconds in persistent mode, or longer than 2× your poll interval in polled mode, see Troubleshooting. Brief Unknown flickers (a single missed frame in persistent mode) are normal and self-recover within 1-2 seconds.\n\nIf you want a real-time indicator of the integration's connection lifecycle, enable the disabled-by-default 'Connection state' diagnostic sensor on the device page.\n\n## Replacing or moving a meter (MAC changed)\n\n\u003e **WARNING: v1 cannot migrate Energy Dashboard history across a MAC change.** If you swap the Atorch J7-C USB power meter for a different physical unit, or otherwise cause its Bluetooth MAC address to change, the new device will be a new config entry with new entity IDs. Long-term statistics — including Energy Dashboard history — are keyed to entity IDs and will not automatically follow the new MAC.\n\nThe procedure in v1:\n\n1. **Delete the old config entry** under **Settings → Devices \u0026 Services**.\n2. **Add the new device via discovery** when it appears (no manual MAC entry).\n3. *(Optional, see warning below)* Use Home Assistant's **entity-rename UI** to graft the new entity IDs onto the old entity IDs to preserve Energy Dashboard continuity and history.\n\n**Entity-rename grafting is the only mitigation available in v1, and incorrect grafting silently corrupts long-term statistics** — e.g. grafting a fresh `total_increasing` counter (starting at 0) onto an existing series whose last value was 12 345 Wh produces a non-monotonic step that HA's statistics engine treats as a counter reset, double-counting the next delta into the Energy Dashboard. Only graft if you understand the implication.\n\nA \"rebind to new MAC\" reconfigure flow that preserves the existing config entry (and therefore the entity IDs and statistics) is a v0.2 candidate — see [Roadmap](#roadmap).\n\n## Troubleshooting\n\n### Device not discovered\n\n- Verify the meter is **powered** (display on; tap the button to wake it).\n- Verify it is **within BLE range** of either a local adapter or an ESPHome proxy.\n- Verify the **HA Bluetooth integration is configured** (Settings → Devices \u0026 Services → Bluetooth) and shows an active adapter or proxy.\n- Discovery requires the meter's local name to be `UC96_BLE` and the GATT service `0000ffe0-0000-1000-8000-00805f9b34fb` to be advertised.\n\n### Sensors Unknown for longer than expected\n\nSee the *First install — what to expect* section above for normal-acquisition windows. If sensors stay Unknown beyond those windows, check the **Connection state** diagnostic sensor (enable it if needed) and download diagnostics (below).\n\nIn polled mode the poll cadence is gated on Bluetooth advertisements: a poll fires on the next advertisement after the configured interval has elapsed, so a meter that advertises infrequently while idle may poll slower than its configured `poll_interval_seconds`.\n\n### Unsupported device variant (repair issue)\n\nIf the integration receives packet types `0x01` or `0x02`, it raises a **repair issue** under **Settings → System → Repairs** identifying the packet-type byte and recommending you file an upstream issue. Dismissing the repair issue is persistent for that config entry's offending packet-type byte (it will not re-surface for the same byte). v1 supports packet type `0x03` only.\n\n### Capturing diagnostic logs\n\nDownload a full diagnostic snapshot via:\n\n**Settings → Devices \u0026 Services → Atorch BLE → device → \"Download diagnostics\"**\n\nTo turn up debug logging temporarily, add this to `configuration.yaml`:\n\n```yaml\nlogger:\n  default: warning\n  logs:\n    custom_components.atorch_ble: debug\n    atorch_ble: debug\n```\n\nThen restart Home Assistant. Remove the entries when finished — debug logging is verbose.\n\n### High parser error count\n\nThe diagnostics download exposes two parser-quality metrics:\n\n- **`parser_error_count`** — cumulative count of `InvalidPacket` exceptions since HA startup.\n- **`parser_error_rate_5m`** — rolling 5-minute ratio in `[0, 1]` of `InvalidPacket` exceptions to received notifications.\n\n**Look at the rate, not the absolute count.** Cumulative counts grow unbounded on long-running installs and are not a useful health signal on their own. The rolling rate is the actionable metric.\n\nThreshold heuristic: **`parser_error_rate_5m \u003e 0.05`** (more than 5% of received notifications in the last 5 minutes are unparseable) indicates a problem, almost always **RF interference** between the meter and the BLE adapter/proxy.\n\nRecommended actions:\n\n1. **Move the meter physically closer** to the adapter or proxy, or reduce obstructions (metal cases, microwaves, dense walls).\n2. If the device is a **confirmed J7-C** and the rate stays elevated after relocation, **file an issue** at the [issue tracker](https://github.com/dallanwagz/j7c_ha/issues) and attach the downloaded diagnostics file.\n\n### Mode change confirmation\n\nSwitching `connection_mode` between persistent and polled via the options flow applies live; sensors may briefly show `Unknown` during the transition while the new mode's first frame is acquired. This is expected and self-recovers within one poll interval.\n\n## Known limitations\n\n- **Atorch J7-C only in v1** (packet type `0x03`). DL24, UD18, and AC meters are detected but unsupported.\n- **No counter reset over BLE.** Energy (Wh) and Capacity (mAh) reset requires the meter's physical button.\n- **Packet type `0x03` only.** Packet types `0x01` and `0x02` raise a repair issue.\n- **Persistent mode holds one ESPHome-proxy connection slot continuously per meter.**\n\n## Removing the integration\n\nTo cleanly remove the integration:\n\n1. Open **Settings → Devices \u0026 Services → Atorch BLE**.\n2. For each Atorch J7-C device, click the device, then **Delete**. This removes the config entry and its entities.\n3. Open **HACS → Integrations → Atorch BLE (J7-C)** and choose **Remove** to uninstall the integration code.\n4. Restart Home Assistant.\n\n**Note on the `atorch-ble` Python package:** Removing the integration via HACS removes the integration code; the `atorch-ble` Python package will remain installed in your Home Assistant environment. It is harmless and will be removed on the next HA container rebuild or environment refresh.\n\n## Roadmap\n\nThe v0.2 backlog:\n\n- RSSI as a disabled-by-default `EntityCategory.DIAGNOSTIC` sensor\n- Reconfigure-flow step that rebinds an existing config entry to a new MAC address (Energy Dashboard history preservation across hardware swap)\n- DL24, UD18, AC-meter packet-type support\n- Auto-create a low-severity repair issue when parser-error-rate exceeds a threshold (currently surfaced only via diagnostics download)\n\n## Protocol references\n\nDocumentation of the Atorch BLE protocol that informed this work:\n\n- adlerweb's reverse-engineering write-up: \u003chttps://www.adlerweb.info/blog/2020/04/19/elektronische-last-atorch-modbus/\u003e\n- NiceLabs `atorch-console`: \u003chttps://github.com/NiceLabs/atorch-console\u003e\n- syssi `esphome-atorch-dl24`: \u003chttps://github.com/syssi/esphome-atorch-dl24\u003e\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdallanwagz%2Fj7c_ha","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdallanwagz%2Fj7c_ha","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdallanwagz%2Fj7c_ha/lists"}