Whytey / moebot-hass-integration

A HomeAssistant integration for MoeBot (and compatible) TUYA mowers.
9 stars 0 forks source link

More robust commands #7

Closed clau-bucur closed 2 months ago

clau-bucur commented 1 year ago

Originally posted by @Ethan-G in https://github.com/Whytey/moebot-hass-integration/issues/1#issuecomment-1522511975

          Could you not just call the right sequence of commands to get around that? For example `return_to_base` could call `pause` then `cancel` then `dock`. Depending on what happens when you call an invalid command, it might need to conditionally do those based on status, or do a try/catch.

Would it be possible to handle the necessary state transitions within the integration, when a command is given? This would make the end-user's life much easier not to have to deal with scripts and what-not in order to get from a mowing state to park, for example.

clau-bucur commented 1 year ago

For now I've created some scripts to handle these transitions and the case when MoeBot is out-of-sync due to robot going offline. They work ok up to now.

The library or the integration could take a similar approach.

script:
  mower_reload_integration:
    variables:
      mower: "vacuum.mower"
    sequence:
      # sensor.mower_state is provided by MoeBot integration
      # sensor.mower_status is provided by localtuya integration
      # If the mower is offline or went offline, MoeBot integration does not correctly reflect it's status, but localtuya does.
      # so a reload of the MoeBot integration would fix it.
      - if: "{{ not has_value('vacuum.mower') or states('sensor.mower_state') != states('sensor.mower_status') }}"
        then:
          - service: homeassistant.reload_config_entry
            data:
              # You will find entry_id for MOEBOT in the file config/.storage/core.config_entries. Search for: "domain": "moebot"
              # It's generated every time the integration is added.
              entry_id: 5b44b77ffdb0e2bdb06275b25b59f028
          - delay: 5

  mower_action:
    variables:
      mower: "vacuum.mower"
      action: "none"
      expected_state: "none"
      successful: false
    sequence:
      - repeat:
          sequence:
            - service: script.mower_reload_integration
            - service: vacuum.{{ action }}
              data:
                entity_id: "{{ mower }}"
            - wait_template: "{{ is_state(mower, expected_state) }}"
              timeout: "00:30"
            - if: "{{ wait.completed }}"
              then:
                - variables:
                    successful: true
          until: "{{ wait.completed or repeat.index >= 3 }}"
      - if: "{{ successful }}"
        then:
          - delay: 5

  mower_mow:
    alias: Mower - Start mowing
    # Chose not to make the mower a variable so that the script shows up as a related entity for the mower device (under Integrations page)
    sequence:
      - service: script.mower_reload_integration
      - if: "{{ is_state('vacuum.mower', 'returning') }}"
        then:
          - service: script.mower_action
            data:
              action: "stop"
              expected_state: "docked"
          - if: "{{ not is_state('vacuum.mower', 'docked') }}"
            then:
              - stop: "Mower does not answer to commands."
                error: true

      - if: "{{ not is_state('vacuum.mower', 'cleaning') }}"
        then:
          - service: vacuum.start
            entity_id: vacuum.mower

  mower_dock:
    alias: Mower - Return to station
    # Chose not to make the mower a variable so that the script shows up as a related entity for the mower device (under Integrations page)
    sequence:
      - service: script.mower_reload_integration

      - if: "{{ is_state('vacuum.mower', 'cleaning') }}"
        then:
          - service: script.mower_action
            data:
              action: "pause"
              expected_state: "idle"
          - if: "{{ not is_state('vacuum.mower', 'idle') }}"
            then:
              - stop: "Mower does not answer to commands."
                error: true

      - if: "{{ is_state('vacuum.mower', 'idle') }}"
        then:
          - service: script.mower_action
            data:
              action: "stop"
              expected_state: "docked"
          - if: "{{ not is_state('vacuum.mower', 'docked') }}"
            then:
              - stop: "Mower does not answer to commands."
                error: true

      - service: vacuum.return_to_base
        entity_id: vacuum.mower
Whytey commented 1 year ago

Hi @clau-bucur , I have been thinking about this ticket and how best to approach. I am wondering if this logic of finding the right transition to the desired state (dock, stop, etc) should be part of the value-add of pymoebot and not part of this integration. Do you have any thoughts?

clau-bucur commented 1 year ago

Hey. IMHO this is rather the integration's job as it exposes the vacuum device to HA, which can receive commands no matter the state the device is in. The logic in the library can remain the same and guard against calls from/to invalid state from the user-code, as to maintain a consistent machine state expected by Tuya/mower.