SwitchBot bot/curtain/meter/contact/motion MQTT ESP32 bridge - Local control

make sure your mqtt ‘set’ messages are not being retained

if your control messages are retained with mqtt, then when the esp32 regains mqtt connections or HA reboots it can rerun the last commands

Ah thanks, I’ll give that a go. That would be a setting in the broker rather than the esp32 code?

correct. what you don’t want is HA/Broker republishing the set messages after a reboot

are you only using thr esp32? if yes the last set message should be the current state anyways, so shouldnt go from closed to open

however if you are also using the switchbot app or switchbot buttons at the same time as esp32, they may have sent the last “close” commands, but the last set mqtt message the esp32 sees is “open”

also you only want your curtain mac address in one esp32s list, not both

That’s a good point. It’s definitely not republishing the last message since a closed curtain will open. I’ve just checked the broker and I don’t have any setting to retain messages on.

I’m not using the app actively. I did have it installed but I’ve not used it for ages. I just uninstalled it just in case it is sending commands in the background (seems unlikely but worth a shot).

Each curtain mac is only in one esp32, one is controlling two, the other just one.

other than something republishing to mqtt, or if you have switchbot schedules, not sure what It could be

the esp32 wont make BLE calls unless an MQTT message is received

you can try turning off HA, then
set your curtain to closed with the switchbot app then turn on HA and see if your curtains move

similar, you can unplug the esp32, set your curtain to closed with the switchbot app, then plug in the esp32 and see if your curtains move

I was able to catch it in the act earlier. What’s interesting is it always follows the curtains becoming unavailable (I’ve seen it do this before), but what’s even more interesting is there seems to be a flurry of open and close actions all within seconds (the last one is me closing manually). Not sure why this is happening, it’s all a bit strange.

Selection_006

First huge thanks for the ESP32 codebase. It’s very nice to have local control and ESP32 feather doesn’t cost much (I wanted LiPo charger on the board, hehe).

Do you know if ESP32 could expose a switch as a light or how should that be done? I want to be able to ask Google/Alexa to turn the lights off and on, one few of which is handled by Switchbot via the ESP32.

@samip537 an easy way is to add or replace the mqtt discovery messages in the code. instead of ‘switch’, use ‘light’

to create both a switch and light entity, you can replace this code…

  client.publish((home_assistant_mqtt_prefix + "/switch/" + deviceName + "/config").c_str(), ("{\"~\":\"" + (botTopic + deviceName) + "\", " +
                 + "\"name\":\"" + deviceName + " Switch\"," +
                 + "\"device\": {\"identifiers\":[\"switchbot_" + deviceMac + "\"],\"manufacturer\":\"" + manufacturer + "\",\"model\":\"" + botModel + "\",\"name\": \"" + deviceName + "\" }," +
                 + "\"avty_t\": \"" + lastWill + "\"," +
                 + "\"uniq_id\":\"switchbot_" + deviceMac + "\", " +
                 + "\"stat_t\":\"~/state\", " +
                 + "\"opt\":" + optiString + ", " +
                 + "\"cmd_t\": \"~/set\" }").c_str(), true);

with this…

  client.publish((home_assistant_mqtt_prefix + "/switch/" + deviceName + "/config").c_str(), ("{\"~\":\"" + (botTopic + deviceName) + "\", " +
                 + "\"name\":\"" + deviceName + " Switch\"," +
                 + "\"device\": {\"identifiers\":[\"switchbot_" + deviceMac + "\"],\"manufacturer\":\"" + manufacturer + "\",\"model\":\"" + botModel + "\",\"name\": \"" + deviceName + "\" }," +
                 + "\"avty_t\": \"" + lastWill + "\"," +
                 + "\"uniq_id\":\"switchbot_" + deviceMac + "\", " +
                 + "\"stat_t\":\"~/state\", " +
                 + "\"opt\":" + optiString + ", " +
                 + "\"cmd_t\": \"~/set\" }").c_str(), true);

  client.publish((home_assistant_mqtt_prefix + "/light/" + deviceName + "/config").c_str(), ("{\"~\":\"" + (botTopic + deviceName) + "\", " +
                 + "\"name\":\"" + deviceName + " Light\"," +
                 + "\"device\": {\"identifiers\":[\"switchbot_" + deviceMac + "\"],\"manufacturer\":\"" + manufacturer + "\",\"model\":\"" + botModel + "\",\"name\": \"" + deviceName + "\" }," +
                 + "\"avty_t\": \"" + lastWill + "\"," +
                 + "\"uniq_id\":\"switchbot_" + deviceMac + "_light\"," +
                 + "\"stat_t\":\"~/state\", " +
                 + "\"opt\":" + optiString + ", " +
                 + "\"cmd_t\": \"~/set\" }").c_str(), true);

you can remove the switch entity is all your bot devices are lights

I got some curtains recently and have no issues like that, there must be something going on in your MQTT.

I would suggest doing a clean install of your MQTT broker if it won’t break anything

But I want that only for those that have mode set to switch?

having both a switch and light entity shouldnt really affect anything, just display the entity you want in your dashboard etc

I dont currently have the code setup to individually chose per device

other option is to create your own HA light entity or group that calls the switch also

If you call it something like “Kitchen_Lights”, google/alexa may auto recognize as light also. In google/alexa you can sometimes manually change the device type also

Thanks for this @devWaves, it’s a great implementation. I have it working with two contact sensors with one small issue. The contacts are reading as TIMEOUT. They worked perfectly on the desk but now that they are fitted to doors I see this. When I open/close a door the state does change and then within a minute, it switches to Timeout.

I’ve probably done something wrong but I can not see it.

I have the esp32 unit only 3 metres away.

Any ideas?

Here is what I am seeing in MQTT Explorer.

I believe if the door is open for over a minute (or something like that) the door sensor will return a timeout value.

from the switchbot app it looks like ‘timeout’ = ‘left open’

these are the values returned from the switchbot contact sensor so I think you have it setup correctly. it has 3 possible values, and isnt a normal binary sensor of just open/closed

you can assume timeout is the same as open I guess.

At some point I will release a new version that has a normal binary door sensor where timeout just converts to open

Ah - thanks for that. I’ll just reverse my logic on the dashboard.

The use case I have is that I have this on a Dog Door that is downstairs. My plan is to know if the door is open or closed without having to go down and physically check. We open and close it from upstairs with a rope in a wardrobe, so there is no motion detected when it open and closes.

What I’m finding is as you said, the door when left open starts as “Open” and then changes to “Timeout”. Trouble is that when it enters the Timeout state, it never changes to “Closed” when I close the door. It is only when it detects motion that it updates the state.

Is there any documentation on ContactA and ContactB (lines 1793-1794)? In particular the role of the Timeout. I thought the timeout was to do with the motion, not the contact but it was quite a while ago I watched a review of this.

I’m thinking of a small change at line 1823 to see if the state is different than the previous stored state.
image
What do you think?

hey @madmat777 the code will already do what you are thinking. what is the rssi of the contact sensor? that plays a big role

I also have the code setup to send an ‘open’ message if the last motion/contact time on the sensor is different then the last captured ‘open’ message. In case an open was missed

the contact sensor is working for me and returns a closed after a timeout. If the esp32 is not picking up a closed service date update message you may need to place it closer

line 1856…

        std::map<std::string, std::string>::iterator itC = contactStates.find(deviceMac);
        if (itC != contactStates.end())
        {
          std::string contactState = itC->second.c_str();
          if (strcmp(contactState.c_str(), contact.c_str()) != 0) {
            shouldPublish = true;
          }

        }
        contactStates[deviceMac] = contact;

the contact sensors are set to always update if there is a state change in the service data scanned for contact or motion. motion/contact are a special case where they always need to be scanned for latest updates

the timeout documentation is here Contact Sensor BLE open API · OpenWonderLabs/python-host Wiki · GitHub

Bit[1:2]:Hal State 0:door close 1:door open 2:timeout not close
...
Byte: 8		Door Status 0:Close 1:Open 2:Timeout not close

Just following up.

It seems that the change is working for me.

Looking at the app with a new contact sensor I can see that there are 3 states that it reports
Open
Left Open (what is currently TIMEOUT in the code)
Closed

cool. I actually like the contact sensor because it has a button on it. I’ve set up the esp32 code so the button can be used. I have moved my previous zwave sensors to other doors, and use the switchbot ones on my house entrances to turn off all light/enable alarm etc when I leave

Missed your reply.

rssi is around -70

Thanks for the documentation link.

I’ve set up the esp32 code so the button can be used.

I have not purchased the contact sensor yet, but this button will be automatically created in HA as a switch?