Guida al DSL di Android per automazioni complesse

Il DSL di automazione può essere utilizzato per creare automazioni più complesse di quelle descritte nella guida al DSL - Automazioni di base su Android.

Sequenziale con più azioni

Sequenziale con più azioni

Un'automazione può eseguire più di un'azione. Ad esempio, al posto del singolo nodo action, potresti avere più nodi action, che vengono eseguiti in ordine sequenziale:

automation {
  sequential {
    starter<_>(...)
    condition {...}
    action {...}
    action {...}
    action {...}
    }
}

Sequenziale con più azioni parallele

Sequenziale con più azioni parallele

Se inserisci più nodi action in un nodo parallel, le azioni vengono eseguite contemporaneamente.

automation {
  sequential {
    starter<_>(...)
    condition {...}
    parallel {
      action {...}
      action {...}
      action {...}
    }
  }
}

Se nel nodo sequential sono presenti action nodi che seguono il nodo parallel, questi attendono l'esecuzione fino al completamento dell'esecuzione di tutti i nodi all'interno del nodo parallel.

Esecuzione condizionale

Per impostazione predefinita, un'automazione esegue i nodi in sequenza o in parallelo. Se hai bisogno di una logica di branching condizionale, ovvero l'esecuzione di azioni o percorsi diversi in base alle condizioni di runtime, utilizza le istruzioni if-then-else, create utilizzando i blocchi DSL del flusso di controllo condizionale: ifThen, elseIf e orElse.

Mentre un nodo condition standard controlla l'intera automazione (se la condizione restituisce false, l'automazione termina immediatamente l'esecuzione), i blocchi ifThen consentono il controllo del flusso di branching:

  • Nodo condition: interrompe l'esecuzione dell'intera automazione (o del percorso di esecuzione corrente) se l'espressione è false.
  • ifThen / elseIf / orElse: valuta le condizioni in ordine. Se una condizione è false, l'esecuzione passa al ramo elseIf successivo, al ramo di riserva orElse o continua con i nodi successivi dell'automazione se non viene soddisfatta nessuna condizione.

Esegui un'azione in base a una condizione

Il blocco ifThen valuta un'espressione condizionale. Se l'espressione restituisce true, vengono eseguite le azioni o i nodi DSL nidificati all'interno del blocco. Se restituisce false, le azioni vengono ignorate e l'automazione continua con i nodi successivi nel flusso sequenziale.

Puoi utilizzare un blocco ifThen autonomo quando vuoi eseguire un'azione in modo condizionale senza bloccare o terminare i nodi successivi nell'automazione:

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
automation {
  sequential {
    val contactState = starter<_>(
      contactSensor,
      ContactSensorDevice,
      BooleanState,
    )
    val lightState = stateReader<_>(
      light,
      DimmableLightDevice,
      OnOff,
    )

    condition {
      // Door opened (contact sensor open)
      expression = contactState.stateValue equals false
    }

    // Conditionally turn on the light if it's off
    ifThen(lightState.onOff equals false) {
      action(light, DimmableLightDevice) { command(OnOff.on()) }
    }

    // Continue executing subsequent actions in the sequential flow
    action(structure) {
      command(AssistantBroadcast.broadcast("The door was opened."))
    }
  }
}

Esegui azioni diverse in base a una condizione

Per eseguire un insieme di azioni quando una condizione è vera e un insieme alternativo di azioni quando è falsa, concatena il blocco .orElse { ... } facoltativo dopo ifThen(...) { ... }:

// When the door is unlocked, turn on the entryway light if it is off;
// otherwise, broadcast a welcome message.
automation {
  sequential {
    val doorLockEvent = starter<_>(
      doorLock,
      DoorLockDevice,
      LockOperationEvent,
    )
    val lightState = stateReader<_>(
      light,
      DimmableLightDevice,
      OnOff,
    )

    condition {
      expression =
        doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock
    }

    ifThen(lightState.onOff equals false) {
      action(light, DimmableLightDevice) { command(OnOff.on()) }
    }.orElse {
      action(structure) {
        command(AssistantBroadcast.broadcast("Welcome home!"))
      }
    }
  }
}

Concatena più condizioni in sequenza

Puoi concatenare uno o più blocchi .elseIf(...) { ... } facoltativi per valutare più condizioni in sequenza. Viene eseguito il primo ramo la cui condizione restituisce true e tutti i rami rimanenti vengono ignorati. Se nessuna delle condizioni restituisce true, viene eseguito un blocco .orElse { ... } facoltativo (se fornito):

// Adjust climate controls based on room temperature changes.
automation {
  sequential {
    val tempStarter = starter<_>(
      tempSensor,
      TemperatureSensorDevice,
      TemperatureMeasurement,
    )

    // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
    ifThen(tempStarter.measuredValue greaterThanOrEquals 2800) {
      action(thermostat, ThermostatDevice) {
        command(
          SimplifiedThermostat.setSystemMode(
            SimplifiedThermostatSystemModeEnum.Cool
          )
        )
      }
    }.elseIf(tempStarter.measuredValue lessThan 1800) {
      // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
      action(thermostat, ThermostatDevice) {
        command(
          SimplifiedThermostat.setSystemMode(
            SimplifiedThermostatSystemModeEnum.Heat
          )
        )
      }
    }.orElse {
      // Otherwise, turn on the fan
      action(fan, FanDevice) {
        command(OnOff.on())
      }
    }
  }
}

Flussi condizionali nidificati

I blocchi condizionali possono essere nidificati all'interno di altri blocchi ifThen, elseIf o orElse, nonché combinati con i nodi parallel, delayFor e stateReader.

I blocchi ifThen, elseIf e orElse eseguono i loro contenuti come flussi sequenziali. Puoi inserire qualsiasi nodo sequenziale all'interno di ogni ramo, inclusi i blocchi action, stateReader, parallel, delayFor e ifThen nidificati.

Ritardi

Puoi introdurre pause nelle tue automazioni utilizzando la parola chiave delayFor, che accetta un argomento java.time.Duration che rappresenta la durata della pausa prima di continuare l'esecuzione. La durata della pausa può variare da cinque secondi a 24 ore.

Ad esempio, per accendere e spegnere una luce quattro volte con una pausa di cinque secondi tra un'operazione e l'altra:

sequential {
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
  delayFor(Duration.ofSeconds(5))
  action(light, OnOffLightDevice) { command(OnOff.toggle()) }
}

Eliminazione dei trigger

La soppressione dell'attivatore è una funzionalità che consente all'automazione di ignorare un starter per un periodo di tempo specificato dopo l'evento di attivazione iniziale. Ad esempio, se l'automazione ha un starter attivato dal rilevamento dei movimenti e se specifichi una durata della soppressione dell'attivatore di cinque minuti, quando il starter si attiva, non si attiverà di nuovo per i cinque minuti successivi. In questo modo, l'automazione non si attiva ripetutamente in rapida successione.

Per applicare la soppressione degli attivatori alla tua automazione, utilizza la parola chiave suppressFor con un argomento java.time.Duration che rappresenta il tempo di attesa prima di rispondere agli attivatori successivi. La durata della soppressione può variare da cinque secondi a 24 ore.

automation {
  sequential {
    val starterNode = starter<_>(device, OccupancySensor, MotionDetection)
    suppressFor(Duration.ofMinutes(30))
    action(light, OnOffLightDevice) { command(OnOff.toggle()) }
}

Tieni presente che la soppressione degli attivatori influisce su tutti i starters di un'automazione che precedono suppressFor.

Limita il numero di esecuzioni

Puoi limitare il numero di volte in cui un'automazione può essere eseguita.

Ad esempio, potresti voler configurare un'automazione una tantum che avvii l'aspirapolvere mentre sei fuori casa per la giornata.

Per farlo, imposta il campo dei metadati maxExecutionCount dell'automazione. L'esempio seguente è un'automazione che può essere eseguita una sola volta:

automation {
  // The automation can only be executed once.
  maxExecutionCount = 1
  // When the door lock state changes
  sequential {
    val doorLockEvent = starter<_>(doorLock, DoorLockDevice, LockOperationEvent)
    // if the door is unlocked
    condition() {
      expression = (doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock)
    }
    // turn the light on
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}

L'automazione viene eliminata immediatamente dopo l'ultima esecuzione e il raggiungimento di maxExecutionCount. La voce della cronologia dell'automazione rimane nella scheda Google Home app (GHA) Attività, inclusa la automation_id.

Imposta gli attributi dei tratti in un'azione

Per impostare il valore di un attributo di un tratto:

  1. Crea un nodo update all'interno di un nodo action, includendo il tratto pertinente come argomento del nodo update:
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
  2. All'interno del nodo update, per ogni attributo da modificare, utilizza una funzione mutatore e passale il nuovo valore. Per formare il nome della funzione mutator:
    1. Usa la lettera iniziale maiuscola per il nome dell'attributo
    2. Aggiungi il prefisso set.
    Ad esempio, per aggiornare un attributo denominato defaultMoveRate, devi utilizzare una funzione mutator denominata setDefaultMoveRate.

Tieni presente che un nodo update può avere più funzioni mutator. Ecco un esempio in cui vengono aggiornati due attributi:

action(device, Fan) {
  update(FanControl) {
    setPercentSetting(50u)
    setRockSetting(FanControlCluster.RockBitmap.rockUpDown)
  }
}