bluetti_mqtt icon indicating copy to clipboard operation
bluetti_mqtt copied to clipboard

added slightly expanded AC180 support

Open alexnathanson opened this issue 10 months ago • 5 comments

I identified the following registers:

device type: 1101 serial_number: 1107 battery type: 6101 battery serial number: 6107 bcu version: 6175 battery percent: 102 output mode: 123 (returns 32 when both loads off, 40 when AC is on, 48 when DC is on, 56 when both on. This is accurate, but may not be exhaustive if there are other additional modes) dc output power: 140 ac output power: 142 dc input power: 144 (this is an educated guess and not tested, because I didn't have a PV module handy) ac input power: 146 power generation might be 1202 or 154, but I can figure it out once I connect a module.

alexnathanson avatar Apr 04 '24 01:04 alexnathanson

@alexnathanson I incorporated your changes into my fork: https://github.com/ftrueck/bluetti_mqtt/ I hope that @ZachGoldberg will give it a try to build a woking HA addon with it. As long as @warhammerkid is MIA we could at least keep the library up and working.

ftrueck avatar May 05 '24 12:05 ftrueck

Thanks for hunting these registers down. there is no "output mode" in mqtt_client.py So for me, this value is not sent out.

bres55 avatar May 28 '24 17:05 bres55

Hope you dont mind me putting it in this way. I have no inclination to create a fork, maybe a spoon :) I have the controls for AC and DC working in Home Assistant now. Nothing clever here I jusy noticed the AC60 had very similar controls. It needs a bit of tidying up. I will experiment a but more, but I am away till next week now, but thought I would share it for now.

AC180.py ..................................................

from enum import Enum, unique #  //???????????????????????
# from alexnathanson
# now put in ac60 similars...29/5/2
from typing import List
from ..commands import ReadHoldingRegisters
from .bluetti_device import BluettiDevice
from .struct import DeviceStruct

class AC180(BluettiDevice):
    def __init__(self, address: str, sn: str):
        self.struct = DeviceStruct()

        #Core
        self.struct.add_swap_string_field('device_type', 110, 6) # went back to these
        self.struct.add_sn_field('serial_number', 116)
        #self.struct.add_swap_string_field('device_type', 1101, 6) #nl
        #self.struct.add_sn_field('serial_number', 1107) #nl

        #Battery Data
        self.struct.add_uint_field('total_battery_percent', 102) #y
        self.struct.add_decimal_field('total_battery_voltage', 6003, 2)

        #Power IO
       # self.struct.add_bool_field('ac_output_on',123) #y? #32 when both loads off, 40 when AC is on, 48 when DC is on, 56 when both on 
        self.struct.add_uint_field('dc_output_power', 140) #y
        self.struct.add_uint_field('ac_output_power', 142) #y
        self.struct.add_uint_field('dc_input_power', 144) #y
        self.struct.add_uint_field('ac_input_power', 146) #y #this is a guess because I didn't have a PV module handy to test

        # Controls (2000)
        self.struct.add_bool_field('ac_output_on', 2011)
        self.struct.add_bool_field('dc_output_on', 2012)

        #History
        #self.struct.add_decimal_field('power_generation', 154, 1)  # try this one Total power generated since last reset (kwh)
        #and back again with new polling range
        self.struct.add_decimal_field('power_generation', 1202, 1) #y unknown  # Total power generated since last reset (kwh)

        # this is usefull for investigating the available data............. how???
        # registers = {0:21,100:67,700:6,720:49,1100:51,1200:90,1300:31,1400:48,1500:30,2000:67,2200:29,3000:27,6000:31,6100:100,6300:52,7000:5}
        # for k in registers:
        #     for v in range(registers[k]):
        #         self.struct.add_uint_field('testI' + str(v+k), v+k)

        super().__init__(address, 'AC180', sn)

    @property
    def polling_commands(self) -> List[ReadHoldingRegisters]:
        return [
            ReadHoldingRegisters(100, 62),
            ReadHoldingRegisters(1200, 90),
            ReadHoldingRegisters(2000, 67),
        ]

    @property
    def logging_commands(self) -> List[ReadHoldingRegisters]:
        return [
            ReadHoldingRegisters(0,21),
            ReadHoldingRegisters(100, 67),
            ReadHoldingRegisters(700,6),
            ReadHoldingRegisters(720,49),
            ReadHoldingRegisters(1100, 51),
            ReadHoldingRegisters(1200, 90),
            ReadHoldingRegisters(1300, 31),
            ReadHoldingRegisters(1400, 48),
            ReadHoldingRegisters(1500, 30),
            ReadHoldingRegisters(2000, 67),
            ReadHoldingRegisters(2200, 29),
            ReadHoldingRegisters(3000, 27),
            ReadHoldingRegisters(6000, 31),
            ReadHoldingRegisters(6100, 100),
            ReadHoldingRegisters(6300, 52),
            ReadHoldingRegisters(7000,5)
        ]

    @property
    def writable_ranges(self) -> List[range]:
        return [range(2000, 2225)]

....................................................................................

T AC180 in HA

bres55 avatar May 29 '24 20:05 bres55

Just want to add I tested this code on AC180P and can confirm it works great:

{'battery_type': 'AC180P', 'battery_serial_number': 23440040765XX, 'bcu_version': Decimal('1039.01')} {} {} {} {'total_battery_percent': 72, 'output_mode': 40, 'dc_output_power': 0, 'ac_output_power': 56, 'dc_input_power': 0, 'ac_input_power': 0} {} {} {'device_type': 'AC180P', 'serial_number': 23440040765XX} {'power_generation': Decimal('0')}

Thanks!

xeonkiev avatar Jul 24 '24 19:07 xeonkiev

Glad it help. I know I was so relieved when it all started to work as intended. I've been able to automate switch on and switch off, and it ticks along nicely. I do wonder if I could get away from having to have the bluetti-mqtt running on the PC, maybe in HA, or trying to get the esp versions working, and I did try them, but without success. So just sticking with what works for now.

bres55 avatar Jul 24 '24 20:07 bres55