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
531 stars 66 forks source link

Ability to control press-hold time dynamically for Bots #54

Closed ScottG489 closed 2 years ago

ScottG489 commented 2 years ago

I'd like to be able to dynamically control how long a press happens for each push signal.

TL;DR Waiting a period of time between switching it on/off while in Switch mode is not the same as specifying a "Press-hold Time" in the app.

Press-hold Time can be configured in the official app, but via this integration (or even the official app) you can't control this duration for each press.

This behavior could be somewhat achieved with this integration by putting the Bot in Switch mode, sending a signal to turn the switch on, and then waiting a dynamic period of time before sending another signal to turn the switch off. There are two problems with this approach though.

  1. I believe this would still require use of the app to set the mode and it would be nice to work completely independently of the app.
  2. The Press-hold Time seems to work independently of whether the button is being pressed where it remains in a depressed state for the period of time specified in the app.

To elaborate on # 2, there seem to be 3 relevant states when in Switch mode:

  1. The button is in an up state (it's sticking out slightly from the front of the button)
  2. A press-hold state which it will stay in for the period of time that's specified for the Press-hold Time setting in the app. In this state the lever is depressed slightly below the bottom of the button.
  3. A hold state where the lever is down and perpendicular to it's default resting position inside the Bot.

Waiting a period of time does not keep the button in a press-hold state where it's depressed, but rather just perpendicular to the Bot. The time the Bot is in a press-hold state is only for the duration of time specified in the app.

So if I want the button to wait in a "held" state for a period of time, there's no way to do this dynamically.

I'm pretty sure this is possible to do client-side because I've done it using their official node-switchbot library. You can see in the example for moving the arm of the Bot where they call switchbot.wait(5000) after device.down(). When "down", it's in the fully depressed "press-hold" state.

Sorry if this was a bit long winded. I have a use case where a perpendicular lever is not adequate and I need it to go to the more obtuse angle where it's below the bottom plain of the Bot.

What are your thoughts? Happy to elaborate more if needed :)

devWaves commented 2 years ago

you can already set the hold time of the bot with the esp32

a holdPress will set the hold value before calling press.

for your bot to hold, the bot mode needs to be set to press

Send a payload to the 'set' topic of the device you want to ...
      Integer 0-100 (for setting bot hold seconds) Example: 5           (for bot only) Does the same thing as <ESPMQTTTopic>/setHold
// SET HOLD TIME ON BOT
  ESP32 will Subscribe to MQTT topic setting hold time on bots
      - <ESPMQTTTopic>/setHold
    send a JSON payload of the device you want to set hold
          example payloads =
            {"id":"switchbotone", "hold":5}
            {"id":"switchbotone", "hold":"5"}
    ESP32 will respond with MQTT on
    - <ESPMQTTTopic>/#
                      ESP32 will respond with MQTT on 'status' topic for every configured device
                        - <ESPMQTTTopic>/bot/<name>/status
                        Example reponses:
                          - <ESPMQTTTopic>/bot/<name>/status
                        Example payload:
                          - {"status":"connected", "command":"5"}
                          - {"status":"errorConnect", "command":"5"}
                          - {"status":"errorCommand", "command":"NOTVALID"}
                          - {"status":"commandSent", "command":"5"}
                          - {"status":"busy", "value":3, "command":"5"}
                          - {"status":"failed", "value":9, "command":"5"}
                          - {"status":"success", "value":1, "command":"5"}
                          - {"status":"success", "value":5, "command":"5"}
                          - {"status":"success", "command":"REQUESTSETTINGS"}
  // holdPress = set bot hold value, then call press on bot (without disconnecting in between)
  ESP32 will Subscribe to MQTT topic to action a holdPress on bots
      - <ESPMQTTTopic>/holdPress
    send a JSON payload of the device you want to set hold then press
          example payloads =
            {"id":"switchbotone", "hold":5}
            {"id":"switchbotone", "hold":"5"}

the time that the esp32 waits is only for the next commands. So if the bot is in the middle of holding, the esp32 will wait for that to finish to send the next command. otherwise the second will fail as "busy"

ScottG489 commented 2 years ago

Great thanks. I think I was looking for something native with the HA integration, but this sounds like it should work. Will give it a shot.

devWaves commented 2 years ago

you can also set the switchbot mode (press vs switch) from the esp32

Here you will want it in press mode. you will most likely not need to change the mode once initially set through the switchbot app or the esp32

devWaves commented 2 years ago

@ScottG489 I forgot to mention that the esp32 code also supports simulating on/off while the bot is in 'press' mode and will use different hold times for on vs off. Which might be more what u want

example: Coffee maker has one button. Holding 5 secs turns it on. Holding 0 secs turns it off

if the esp32 loses power it will use an mqtt retained message to set the last state

if the state gets messed up, you need to mqtt call set STATEON or STATEOFF

on/off 'switch' mode is a push/pull style and probably not what you want from your description

use this in the code ...

/*** Bots in PRESS mode to simulate ON/OFF - ESP32 will try to keep track of the ON/OFF state of your device while in PRESS mode***/
      // Add bots while in PRESS mode that will simulate ON/OFF. Default state will be used if no MQTT retained on state topic
      // false = default state = OFF
      // true = default state = ON
      // If the state is incorrect, call set STATEOFF or STATEON
      static std::map<std::string, bool> botsSimulateONOFFinPRESSmode = {
        /*{ "switchbotone", false },
          { "switchbottwo", false }*/
      };

      //Add bots OFF hold time for simulated ON/OFF, if not in list, the current hold value will be used. Device must be in botsSimulateONOFFinPRESSmode list
      static std::map<std::string, int> botsSimulatedOFFHoldTimes = {
        /*{ "switchbotone", 0 },
          { "switchbottwo", 10 }*/
      };

      //Add bots ON hold time for simulated ON/OFF, if not in list, the current hold value will be used. Device must be in botsSimulateONOFFinPRESSmode list
      static std::map<std::string, int> botsSimulatedONHoldTimes = {
        /*{ "switchbotone", 15 },
          { "switchbottwo", 1}*/
      };