devWaves / SwitchBot-MQTT-BLE-ESP32

Allows for multiple SwitchBot bots and curtains to be controlled via MQTT sent to ESP32. ESP32 will send BLE commands to switchbots and return MQTT responses to the broker. Also supports Temperature, Motion, Contact sensors
MIT License
530 stars 66 forks source link

Support for Blind Tilt #117

Open craiggenner opened 1 year ago

craiggenner commented 1 year ago

Any thoughts on supporting the new Blind Tilt?

I had hopped that it would work as a curtain, but no such luck that I can tell.

I'm happy to be pointed in the right direction and make attempts to snoop on the Bluetooth traffic and commands if anyone can guide me. (Running android if that helps)

rasmusdencker commented 1 year ago

So @craiggenner I got it working, and it was very simple.

Turns out it's indeed treated as an ordinary curtain bot with the same commands like you presumed; but as "service data", the Blind Tilt sends the letter 'x', whereas the normal Curtain Bot sends a five-character string, checked for in this if statement:

https://github.com/devWaves/SwitchBot-MQTT-BLE-ESP32/blob/8faf36e8ea33aa7e822681cbb2d8a2284fbd9eee/PlatformIO%20Files/SwitchBot-BLE2MQTT-ESP32/src/SwitchBot-BLE2MQTT-ESP32.cpp#L4101-L4103

Swap that for

 if (aLength < 5 && aValueString != "x") {
  return false;
}

And you should be golden. This is a quick hack, though; where 100 is usually "fully open" and 0 "fully closed", on the Blind Tilt 0 is closed down, 50 is fully open, and 100 is closed up. This means that if you send the OPEN command, it actually closes the blinds. You need to open them to 50% to get them physically fully opened.

That could obviously be fixed by treating them as an entirely different device, but that'd require some more coding.

zolakk commented 1 year ago

Could there be more needed? I made that change and put in my new blind under the allCurtains like this - MACs match what's shown in the app:

`static std::map<std::string, std::string> allCurtains = {

{ "curtain1", "DC:37:72:C1:DB:4B" }, { "curtain2", "F5:4A:CF:D0:8E:6E"}, { "curtain3", "E0:FB:44:7D:5C:50" }, { "blind", "EF:FF:0B:D8:5F:F9" } };` and I'm still not getting anything like battery, rssi, attributes, etc on the switchbot/switchbotESPName/curtain topic like all my other curtains that work fine. The blind doesn't respond to the ESP either, but does in the app. If it makes a difference the app is reporting firmware 1.2 on the blind

rasmusdencker commented 1 year ago

@zolakk so, after posting, I realized that it only works for controlling the blinds. I haven't played with Bluetooth development much, but the service data is meant to report precisely the data you're missing. Since the string version of the service data is just an x, it's clear that data is missing; hence the hack will not allow reading the current state. I don't really know why since it reports itself as a WoCurtain, so I'd expect it to report in the same format as the standard Curtain bots.

There's some work going on over here where they seem to have figured it out. That library is the one used by the core Home Assistant SwitchBot integration. I think the main reason people end up here is that Home Assistants built-in Bluetooth support is quite useless in practice for several reasons; for instance, if you run it on a Pi, the Bluetooth radio is not great and has considerable interference with the WiFi module. Of course, that's also an issue on the ESP32; however, since it's dedicated to that, it's easier to program several and place them closer to the controlled devices.

During my research, I discovered that a few months ago, it was made possible to configure ESPHome to act as a Bluetooth Proxy for Home Assistant so that you can use the Core SwitchBot support instead of bridging over MQTT. So I tested it out, and it found my Curtain Bots, but I have yet to test beyond that point.

https://esphome.github.io/bluetooth-proxies/

craiggenner commented 1 year ago

@rasmusdencker thanks for that, unfortunately I get the same results as @zolakk :-(

I use this project as the ESPHome Bluetooth Proxy for Home Assistant doesn't detect my curtains for some reason, never been able to figure that one out.

Good news that someone looks to be figuring out how to communicate with the Blind Tilt.

zolakk commented 1 year ago

Any chance anyone has had luck on this? I've tried looking at it myself but I'm completely lost in the code as I don't have really any esp or bluetooth experience on the code end. I'll keep hacking at it myself when I get time, maybe I'll get an a-ha moment

craiggenner commented 1 year ago

Sorry, I haven't.

I'm currently using the Home Assistant proxy route to control my Blind Tilt.

mschingel commented 1 year ago

@devWaves Also hoping Blinds are added. BLE proxy doesn’t work for me as it’s slower than MQTT. Just tried with grouping 3 blinds together. Which is odd and unknown to me.

I don’t mind that the blinds open position is 50. A cover template in HA corrects that and allows for your preferred close status. For me I like closed up position for the blinds. The battery life stats is also a nice touch.

The new hub 2 sets closed to down position which doesn’t work for me.

zolakk commented 1 year ago

I think I made some actual headway. My blind appears to respond over MQTT with the battery and lights reporting correctly. Not so sure on rssi and calibration since I can't figure out where if anywhere in the app that's reported to compare. I seem to remember running through the calibration a few times in the past so I think that's probably mis-reporting. The position status I can't figure out though. Looking at pySwitchbot they have the curtain as this:

if mfr_data and len(mfr_data) >= 11:
        device_data = mfr_data[8:11]
    elif data:
        device_data = data[3:6]
    else:
        return {}

    _position = max(min(device_data[0] & 0b01111111, 100), 0)
    _in_motion = bool(device_data[0] & 0b10000000)
    _light_level = (device_data[1] >> 4) & 0b00001111
    _device_chain = device_data[1] & 0b00000111

but the blind is this:

if mfr_data is None:
        return {}

    device_data = mfr_data[6:]

    _tilt = max(min(device_data[2] & 0b01111111, 100), 0)
    _in_motion = bool(device_data[2] & 0b10000000)
    _light_level = (device_data[1] >> 4) & 0b00001111
    _calibrated = bool(device_data[1] & 0b00000001)

so I'm thinking it must be in a different byte on the blind, plus it looks like my blind only reports an aLength of 3 where my curtains an aLength of 6.

The current code for those values in the processAdvData method I have duplicated from the curtain as, but I'm not sure what needs to change here or if that's the right spot to be looking.

    uint8_t byte1 = (uint8_t) aValueString[1];
    uint8_t byte2 = (uint8_t) aValueString[2];
    uint8_t byte3 = (uint8_t) aValueString[3];
    uint8_t byte4 = (uint8_t) aValueString[4];

    bool calibrated = byte1 & 0b01000000;
    //int battLevel = byte2 & 0b01111111;
    int currentPosition = 100 - (byte1 & 0b01111111);
    int lightLevel = (byte4 >> 4) & 0b00001111;
krisf12 commented 10 months ago

I got a motion sensor showing properly but my blind tilt that I'm using as "curtains" is showing unknown status in HA. Any idea why? The mac address is correct and I made the changes to line 4101.

Thanks!