Skip to content

F3800 Works!, with AC relay! #28

Description

@jfarre20

Hello, got my F3800 working with AC toggle!

Tested against a real F3800 + BP3800 expansion via an ESPHome Bluetooth proxy (M5Stack
AtomS3) with SolixBLE 3.7.0 / HaSolixBLE 3.3.0. Connect + ECDH/AES negotiation, telemetry decode, and AC control all work.

I had my Claude code figure it out, it was really neat to watch it go. AI is wild.

It had me make 3 changes,

First: SolixBLE must be 3.7.0 in the manifest.json

"requirements": ["SolixBLE==3.7.0"],

Second: It made this patch in sensor.py just below the Logger

# --- F3800 fix (drop-in patch) -------------------------------------------- #
# Upstream HaSolixBLE/SolixBLE references `power_in` on the F3800, but the
# (untested) F3800 class never defines it -> AttributeError -> the whole sensor
# platform fails and the device shows "no entities". Add it here as
# AC-in + solar-in, at import time (runs before entities are created).
if not hasattr(F3800, "power_in"):
    F3800.power_in = property(
        lambda self: self.ac_power_in + self.solar_power_in
    )
# -------------------------------------------------------------------------- #

and third: it did a few changes to switch.py, attached here.

switch.py

# --------------------------------------------------------------------------- #
# F3800 control extension (monkeypatch — see module docstring)                #
# --------------------------------------------------------------------------- #
_F3800_CMD_AC_OUTPUT = "404a"
_F3800_CMD_DC_OUTPUT = "404b"
_F3800_PAYLOAD_ON = "a10121a2020101"
_F3800_PAYLOAD_OFF = "a10121a2020100"


def _patch_f3800_control() -> None:
    """Add output-control methods to the SolixBLE F3800 class if absent."""

    async def turn_ac_on(self: SolixBLEDevice) -> None:
        await self._send_command(
            cmd=bytes.fromhex(_F3800_CMD_AC_OUTPUT),
            payload=bytes.fromhex(_F3800_PAYLOAD_ON),
        )

    async def turn_ac_off(self: SolixBLEDevice) -> None:
        await self._send_command(
            cmd=bytes.fromhex(_F3800_CMD_AC_OUTPUT),
            payload=bytes.fromhex(_F3800_PAYLOAD_OFF),
        )

    async def turn_dc_on(self: SolixBLEDevice) -> None:
        await self._send_command(
            cmd=bytes.fromhex(_F3800_CMD_DC_OUTPUT),
            payload=bytes.fromhex(_F3800_PAYLOAD_ON),
        )

    async def turn_dc_off(self: SolixBLEDevice) -> None:
        await self._send_command(
            cmd=bytes.fromhex(_F3800_CMD_DC_OUTPUT),
            payload=bytes.fromhex(_F3800_PAYLOAD_OFF),
        )

    if not hasattr(F3800, "turn_ac_on"):
        F3800.turn_ac_on = turn_ac_on
        F3800.turn_ac_off = turn_ac_off
        F3800.turn_dc_on = turn_dc_on
        F3800.turn_dc_off = turn_dc_off
        _LOGGER.debug("Patched F3800 with AC/DC output control methods")


_patch_f3800_control()

Env: SolixBLE 3.7.0, HaSolixBLE 3.3.0, ESPHome 2026.5.1 bluetooth_proxy on ESP32-S3.

I'm able to turn AC on and off, DC is a bit weird it works but home assistant doesn't seem to recognize it the state change. I'm all out of claude credits for the week, so thought I'd just report my findings - or rather its findings... I just paid for the tokens ;)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions