Proposition d'implémentation pour le contrôle des Portes de Garage (GarageDoorController)

Bonjour à tous, et un grand merci au(x) développeur(s) pour le plugin Alexa Smarthome (ASH) qui fonctionne à merveille !

Je me permets d’ouvrir ce sujet pour proposer une petite évolution. Actuellement, lorsqu’on déclare un équipement avec la catégorie GARAGE_DOOR dans le plugin, ce dernier ne remonte nativement qu’un ContactSensor (l’état ouvert/fermé). Il est donc impossible d’actionner la porte de garage à la voix nativement, beaucoup d’utilisateurs devant ruser en déclarant leur garage comme un « Volet » (EXTERIOR_BLIND).

En regardant la documentation d’Amazon et le code du plugin, j’ai développé une implémentation propre qui permet de rajouter les actions d’ouverture et de fermeture, en utilisant l’interface Alexa.ModeController couplée aux sémantiques Position.Up et Position.Down. Je l’ai testée sur mon installation et cela fonctionne parfaitement avec les commandes « Alexa, ouvre/ferme la porte ».

Voici le code pour intégrer cette fonctionnalité.

1. Création du fichier core/class/ash_GarageDoorController.class.php :

<?php
require_once dirname(__FILE__) . '/../../../../core/php/core.inc.php';

class ash_GarageDoorController {

	private static $_OPEN = array('GB_OPEN', 'GARAGE_OPEN'); 
	private static $_CLOSE = array('GB_CLOSE', 'GARAGE_CLOSE');
	private static $_STATE = array('GARAGE_STATE', 'BARRIER_STATE');

	public static function discover($_device, $_eqLogic) {
		$return = array();
		$return['capabilities'] = array();

		$return['capabilities']['Alexa.GarageDoorController'] = array (
			'type' => 'AlexaInterface',
			'interface' => 'Alexa.ModeController',
			'instance' => 'GarageDoor.Position',
			'version' => '3',
			'properties' => array (
				'supported' => array(array('name' => 'mode')),
				'proactivelyReported' => false,
				'retrievable' => false,
			),
			'capabilityResources' => array (
				'friendlyNames' => array(
					array('@type' => 'asset', 'value' => array ('assetId' => 'Alexa.Setting.Opening'))
				),
			),
			'configuration' => array (
				'ordered' => false,
				'supportedModes' => array (
					array(
						'value' => 'Position.Up',
						'modeResources' => array('friendlyNames' => array(array('@type' => 'asset', 'value' => array('assetId' => 'Alexa.Value.Open'))))
					),
					array(
						'value' => 'Position.Down',
						'modeResources' => array('friendlyNames' => array(array('@type' => 'asset', 'value' => array('assetId' => 'Alexa.Value.Close'))))
					)
				)
			),
			'semantics' => array (
				'actionMappings' => array (
					array (
						'@type' => 'ActionsToDirective',
						'actions' => array ('Alexa.Actions.Open', 'Alexa.Actions.Raise'),
						'directive' => array ('name' => 'SetMode', 'payload' => array ('mode' => 'Position.Up'))
					),
					array (
						'@type' => 'ActionsToDirective',
						'actions' => array ('Alexa.Actions.Close', 'Alexa.Actions.Lower'),
						'directive' => array ('name' => 'SetMode', 'payload' => array ('mode' => 'Position.Down'))
					),
				),
				'stateMappings' => array (
					array ('@type' => 'StatesToValue', 'states' => array ('Alexa.States.Open'), 'value' => 'Position.Up'),
					array ('@type' => 'StatesToValue', 'states' => array ('Alexa.States.Closed'), 'value' => 'Position.Down'),
				),
			),
		);

		foreach ($_eqLogic->getCmd() as $cmd) {
			if (in_array($cmd->getGeneric_type(), self::$_OPEN)) {
				$return['cookie']['GarageDoorController_setOpen'] = $cmd->getId();
			}
			if (in_array($cmd->getGeneric_type(), self::$_CLOSE)) {
				$return['cookie']['GarageDoorController_setClose'] = $cmd->getId();
			}
			if (in_array($cmd->getGeneric_type(), self::$_STATE)) {
				$return['capabilities']['Alexa.GarageDoorController']['properties']['retrievable'] = true;
				$return['cookie']['GarageDoorController_getState'] = $cmd->getId();
			}
		}

		if (!isset($return['cookie']['GarageDoorController_setOpen']) || !isset($return['cookie']['GarageDoorController_setClose'])) {
			return array();
		}

		return $return;
	}

	public static function needGenericType(){
		return array(
			__('Ouvrir',__FILE__) => self::$_OPEN,
			__('Fermer',__FILE__) => self::$_CLOSE,
			__('Etat',__FILE__) => self::$_STATE
		);
	}

	public static function exec($_device, $_directive) {
		if ($_directive['header']['name'] == 'SetMode') {
			$mode = $_directive['payload']['mode'];
			if ($mode == 'Position.Up' && isset($_directive['endpoint']['cookie']['GarageDoorController_setOpen'])) {
				$cmd = cmd::byId($_directive['endpoint']['cookie']['GarageDoorController_setOpen']);
				if (is_object($cmd)) $cmd->execCmd();
			} else if ($mode == 'Position.Down' && isset($_directive['endpoint']['cookie']['GarageDoorController_setClose'])) {
				$cmd = cmd::byId($_directive['endpoint']['cookie']['GarageDoorController_setClose']);
				if (is_object($cmd)) $cmd->execCmd();
			}
		}
		return self::getState($_device, $_directive);
	}

	public static function getState($_device, $_directive) {
		$return = array();
		$cmd = null;
		if (isset($_directive['endpoint']['cookie']['GarageDoorController_getState'])) {
			$cmd = cmd::byId($_directive['endpoint']['cookie']['GarageDoorController_getState']);
		}
		if (!is_object($cmd)) return $return;

		$value = $cmd->execCmd();
		if ($cmd->getSubtype() == 'binary' && $cmd->getDisplay('invertBinary') == 1) {
			$value = ($value) ? 0 : 1;
		}

		$modeValue = ($value) ? 'Position.Up' : 'Position.Down';

		$return[] = array(
			'namespace' => 'Alexa.ModeController',
			'instance' => 'GarageDoor.Position',
			'name' => 'mode',
			'value' => $modeValue,
			'timeOfSample' => date('Y-m-d\TH:i:s\Z', strtotime($cmd->getValueDate())),
			'uncertaintyInMilliseconds' => 0,
		);
		return array('properties' => $return);
	}
}

2. Modifications dans le fichier core/class/ash.class.php : Ajouter l’include en haut du fichier avec les autres :

include_file('core', 'ash_GarageDoorController', 'class', 'ash');

Et modifier la déclaration de la catégorie GARAGE_DOOR dans la fonction getSupportedType() :

'GARAGE_DOOR' => array('name' => __('Porte de garage', __FILE__), 'skills' => array('ContactSensor', 'GarageDoorController')),

Il suffit ensuite d’assigner les types génériques d’action appropriés (Bouton d’ouverture / Bouton de fermeture) sur un Virtuel pour que les commandes remontent proprement dans Alexa.

Serait-il possible d’étudier cette piste pour l’intégrer officiellement dans une prochaine mise à jour du plugin (en Beta dans un premier temps) ? Cela permettrait d’avoir une gestion native et propre des portes de garage pour tous les utilisateurs, sans devoir bidouiller.

PS : Je peux faire une PR sur le depot du plugin-ash si vous le souhaitez.

Merci de votre retour et encore bravo pour le travail accompli !

Bonne soirée

Salut,

Oui fais une PR :wink:

Copier/coller du code depuis community c’est quand même galère

1 « J'aime »

C’est fait. Merci pour ta réponse.