Centralisation par scénario de la création des Custom Apps sous Awtrix 3

Bonjour,

image

Il est possible de flasher la matrice d’affichage Ulanzi Smart Pixel clock TC001 avec un firmware custom appelé « Awtrix 3 » (ancien nom : Awtrix Light) :
https://blueforcer.github.io/awtrix-light/#/

La matrice est alors ensuite pilotable via API HTTP ou MQTT.

J’ai créé un scénario permettant de lancer les Custom Apps permises par ce FW, en passant tous les paramètres via tag à des commandes de l’équipement jMQTT.
Cela pourrait également fonctionner en théorie avec MQTT Manager, mais je n’ai pas testé.

Versions du tuto
16/04/2024 : ajout gestion du gradient de couleur, et plus généralement des arrays de couleur en tant que paramètres

Principe

Il y a 3 Customs Apps disponibles (app1 / app2 / app3).
Il est facile d’en rajouter des supplémentaires si besoin une fois qu’on a compris le principe.

Equipement jMQTT

Indications pour l’équipement jMQTT

Le champ « inscrit au topic » de l’équipement jMQTT sera « [PREFIX]/# ». Par exemple dans mon cas « awtrix_6cc048/# »

Pour chacune des customs Apps programmables (App1 / App2 / App3) il faut créer, avec « x » qui varie selon la custom App. :

  • Une commande Action de type « défaut » : « Custom_App_x »

Le topic sera « [PREFIX]/custom/Appx ».

Bien cocher « Pub. Auto »

  • Une commande Info de type « binaire » appelée « Loop_appx »

Le topic sera « [PREFIX]/ /stats/loop », et le chemin json « [Appx] ».

2 autre commandes sont également à créer :

  • Une commande Action" de type « message » appelée « Switch to app »

Le topic sera « [PREFIX]/switch », et la valeur « {« name »: »#message#« } ».

  • Une commande Action" de type « défaut » appelée « next app ».

Le topic sera « [PREFIX]/nextapp ».

Bloc code du scénario

A noter la présence de beaucoup de debug en log. Je verrai par la suite s’il faut élaguer un peu.
Je ne suis pas programmeur, donc je suis preneur de toutes les remarques / suggestion d’amélioration du code.
Je n’ai pas non plus encore testé tous les paramètres : merci donc de me faire vos remontées si quelque chose ne fonctionne pas. Je partage justement le code pour élargir les tests.

//Initialisation de différentes variables
//---------------------------------------------------------
$commande_flag = 0;

$tags = $scenario->getTags();

//Copie dans une variable spécifique pour éviter une confusion dans les tags quand exécution simultanée du scénario
$array = $tags;

$app = strtolower($array['#app#']);
$mode = strtolower($array['#mode#']);

$print_array_init = print_r($array,true);
$scenario->setLog('array initial :' ."\n" .$print_array_init ."\n");

//---------------------------------------------------------

foreach($array as $key => $value) {
	//On enlève les # dans le nom des tags / clés
  	$old_key = $key;
    $new_key = str_replace("#","",$key);
  	$array[$new_key] = $array[$old_key];
  	unset($array[$old_key]);
	//On remplace true/false par 1/0 car sinon le json_encode rajoute des "" autour de true/false ce qui fait que ce n'est pas pris en compte par Awtrix   	
  	if ($array[$new_key] === "true")
		$array[$new_key] = 1;
  	elseif ($array[$new_key] === "false")
		$array[$new_key] = 0;

//si le tag "text" est une commande Jeedom débutant par #[ alors elle est forcément interprétée avec sa valeur
// Si on veut passer dans le json le nom de la commande pour qu'ensuite la valeur dans l'app sur l'Awtrix soit automatiquement mise à jour lorsqu'elle change dans Jeedom il faut que le nom de la commande soit passé dans le tag sans "#'.
// L'ajout des '#' est alors effectué dans le tableau ci-dessous :
	if ((strpos($array[$new_key],'[') === 0) && (strpos($array[$new_key],'#') != 1) && (strrpos($array[$new_key],']') == (strlen($array[$new_key])-1))) {
		$scenario->setLog('PRESENCE D\'AU MOINS UNE COMMANDE INFO  !' ."\n");
       	$array[$new_key] = '#' .$array[$new_key];
      	$array[$new_key] .= '#';
      	//Création d'un array avec les keys comportant une commande Jeedom
      	$arr_commande[] = $new_key;
 		//On flag la présence d'une commande Jeedom
      	$commande_flag = 1;
    }

  

if ((strpos($array[$new_key],'[') === 0) && (strpos($array[$new_key],'#') == 1) && (strrpos($array[$new_key],']') == (strlen($array[$new_key])-1))) {
		$scenario->setLog('PRESENCE D\'UN ARRAY DE COULEUR  !' ."\n");
       	$array[$new_key] = str_replace('#','"#', $array[$new_key]);
      	$array[$new_key] = str_replace(',','",', $array[$new_key]);
      	$array[$new_key] = str_replace(']','"]', $array[$new_key]); 
      	//Création d'un array avec les keys comportant un array de couleur Jeedom
      	$arr_array_couleur[] = $new_key;
 		//On flag la présence d'un array de couleur
      	$array_couleur_flag = 1;
    }
  

}

$print_arr_commande = print_r($arr_commande,true);
$scenario->setLog('array keys commandes Jeedom :' ."\n" .$print_arr_commande ."\n");
$print_arr_array_couleur = print_r($arr_array_couleur,true);
$scenario->setLog('array keys array de couleur :' ."\n" .$print_arr_array_couleur ."\n");



//On nettoie pour enlever les tags "mode" et "app"
unset($array['app']);
unset($array['mode']);


/*
//Si l'option rainbow = 1 est présente, alors on désactive les options fadeText gradient et blinktext qui ne sont pas compatibles (dans un but de clarté : en pratique même si fadeText et gradient sont maintenus dans le json l'option rainbow est prioritaire)
//if (array_key_exists(("rainbow" && ("gradient" || "fadeText")),$tags)) {
if ((array_key_exists('rainbow',$array) && $array['rainbow'] == 1) && (array_key_exists('gradient',$array) || array_key_exists('fadeText',$array) || array_key_exists('blinkText',$array))) {
	$scenario->setLog('ATTENTION --> INCOMPATIBILITE ENTRE OPTIONS : ON NE CONSERVE QUE RAINBOW' ."\n");
	if (array_key_exists('gradient',$array))
		unset($array['gradient']);
  	if (array_key_exists('fadeText',$array))
		unset($array['fadeText']);
}
*/


//On est obligé de convertir les commandes Jeedom de type #[XXX][YYY][ZZZ]# par leur ID (sous format #id#) afin que lorsqu'elle est mise à jour cela soit pris en compte dans jMQTT par la configuration "request" de la commande action jMQTT pour lancer la customapp
if ($commande_flag == 1) {
	$i = 0;
  	foreach($arr_commande as $value) {
  		$array[$value] = '#' .cmd::byString($array[$value])->getId() .'#';	
  		$scenario->setLog('Id' .$i .' : ' .':' .cmd::byString($array[$value])->getId() ."\n");
      	$i++;
	}
}


//On crée le json à passer à l'Awtrix
$json = json_encode($array);


#On enlève les " rajoutés par le json_encode à l'ID de la commande Jeedom
if ($commande_flag == 1) {
	$json = str_replace(':"#',':#', $json);
	$json = str_replace('#"','#', $json);
}

#On enlève les " rajoutés par le json_encode dans l'array de couleur
if ($array_couleur_flag == 1) {
	$json = str_replace('"[\"','["', $json);
	$json = str_replace('\\"','"', $json);
	$json = str_replace('"]"','"]', $json);
}
  

$scenario->setLog('json envoyé : ' .':' .$json ."\n");


//Selon le tag, on choisit le nom de l'app custom
//Après lancement de l'app custom : on switche l'affichage vers elle
switch ($app) {
    case 'app1':
		if ($mode == 'on') {
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_1]#')->setConfiguration('request', $json)->save();
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_1]#')->execCmd();
			//On bascule l'affichage sur la nouvelle app
    		$option1 = array('title'=>'', 'message'=> 'App1');
    		cmd::byString("#[Chambre_Anna][Awtrix_jMQTT][Switch to app]#")->execCmd($option1, $cache=0);
		}
    	if ($mode == 'off') {
        	jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_1]#')->setConfiguration('request', '')->save();
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_1]#')->execCmd();	
    		//Si App3 disparaît du json [PREFIX]/stats/loop, elle ne revient pas toute seule à 0 dans jMQTT mais garde sa dernière valeur connue. On force donc son passage à 0
          	cmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Loop_app1]#')->event(("0"));
          	// workaround pour un petit bug : Current App ne se réinitialise pas quand la custom app est arrêtée
          	jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Next app]#')->execCmd();
        }
    
		$config_app1 = cmd::byString("#[Chambre_Anna][Awtrix_jMQTT][Custom_App_1]#")->getConfiguration();
		$print_config_app1 = print_r($config_app1,true);
		$scenario->setLog('__Config_App1 après modif --> '.$print_config_app1 ."\n");   
    
    break;
    
    case 'app2':
		if ($mode == 'on') {
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_2]#')->setConfiguration('request', $json)->save();
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_2]#')->execCmd();
    		//On bascule l'affichage sur la nouvelle app
    		$option2 = array('title'=>'', 'message'=> 'App2');
    		cmd::byString("#[Chambre_Anna][Awtrix_jMQTT][Switch to app]#")->execCmd($option2, $cache=0);
        }
    	if ($mode == 'off') {
        	jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_2]#')->setConfiguration('request', '')->save();
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_2]#')->execCmd();	
    		//Si App3 disparaît du json [PREFIX]/stats/loop, elle ne revient pas toute seule à 0 dans jMQTT mais garde sa dernière valeur connue. On force donc son passage à 0
          	cmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Loop_app2]#')->event(("0"));
          	// workaround pour un petit bug : Current App ne se réinitialise pas quand la custom app est arrêtée
          	jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Next app]#')->execCmd();
        }

		$config_app2 = cmd::byString("#[Chambre_Anna][Awtrix_jMQTT][Custom_App_2]#")->getConfiguration();
		$print_config_app2 = print_r($config_app2,true);
		$scenario->setLog('__Config_App2 après modif --> '.$print_config_app2 ."\n");    
    
    break;
    
    case 'app3':
		if ($mode == 'on') {
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_3]#')->setConfiguration('request', $json)->save();
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_3]#')->execCmd();
    		$option3 = array('title'=>'', 'message'=> 'App3');
    		cmd::byString("#[Chambre_Anna][Awtrix_jMQTT][Switch to app]#")->execCmd($option3, $cache=0);
        }
    	if ($mode == 'off') {
        	jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_3]#')->setConfiguration('request', '')->save();
    		jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Custom_App_3]#')->execCmd();	
    		//Si App3 disparaît du json [PREFIX]/stats/loop, elle ne revient pas toute seule à 0 dans jMQTT mais garde sa dernière valeur connue. On force donc son passage à 0
          	cmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Loop_app3]#')->event(("0"));
          	// workaround pour un petit bug : Current App ne se réinitialise pas quand la custom app est arrêtée
          	jMQTTCmd::byString('#[Chambre_Anna][Awtrix_jMQTT][Next app]#')->execCmd();
        }

		$config_app3 = cmd::byString("#[Chambre_Anna][Awtrix_jMQTT][Custom_App_3]#")->getConfiguration();
		$print_config_app3 = print_r($config_app3,true);
		$scenario->setLog('__Config_App3 après modif --> '.$print_config_app3 ."\n");
    	
    break;
}



$print_array_modif = print_r($array,true);
$scenario->setLog('array modifié :' ."\n" .$print_array_modif);

Les paramètres pour la custom Apps Awtrix sont à passer au scénario via tags.

Commentaires / Instructions spécifiques pour piloter le scénario :

2 tags sont obligatoires :

  • « app » : pour désigner quelle Custom App utiliser

Valeurs possibles : app1 / app2 / app3

  • « mode » : pour déterminer s’il faut démarrer ou arrêter la Custom App

Valeur possible : on / off

Les couleurs sont à passer au format #hexadécimal.
Les arrays de couleur (comme pour la commande « gradient » par exemple) sont à passer sous format [#couleur1_hexa,#couleur2_hexa].

Attention : certains paramètres sont incompatibles entre eux.
Voir documentation pour « rainbow » « gradient » « fadeText » et « blinkTest ».
A noter que si « rainbow » et « gradient » sont simultanément à « true » alors c’est « rainbow » qui est pris en compte par l’Awtrix

Pour savoir si une Custom App est lancée ou non, il suffit de consulter la commande Info appelée « Loop_appx ».

Après le démarrage d’une Custom App l’affichage de l’Awtrix est basculé immédiatement sur celle-ci.

Exemples de tags :

app=app1
mode=on
text="Il fait grand soleil"
center=true
duration=20
rainbow=true
app=app1
mode=on
text="Il fait grand soleil"
center=true
duration=20
gradient="[#AD0E8D,#7D00D1]"
app=app1
mode=off

Passage de commandes en paramètres

Il est possible de passer des commandes Jeedom de type info pour n’importe quel paramètres.

Ainsi, si « Pub. Auto » est bien sélectionné pour la commande jMQTT correspondant à la Custom App, une fois la Custom App lancée il suffira juste de modifier (par exemple avec une commande « event » dans un scénario) la valeur de la commande de type Info pour que cette nouvelle valeur soit répercutée dans l’affiche de l’Awtrix. C’est la meilleure méthode car elle évite de relancer la Custom App et ainsi potentiellement saturer la mémoire de l’Awtrix (ce qui peut faire crasher l’Awtrix).

Instructions spécifiques pour l’utilisation de commande de type Info :

Il ne faut pas mettre les # dans le nom de la commande

Il faut mettre la commande entre guillemets (au cas où elle comporte des espaces)

Pour les paramètres de type Booléen (true/false), la valeur de la commande de type Info doit être égale à 0 / 1 avec :

  • true = 1
  • false = 0.

Exemple de tags avec commandes Info :

app=app1
mode=on
text="[Technique][Variables][TEXTE]"
center=false
duration=20
rainbow="[Technique][Variables][BOOL RAINB]"
app=app2
mode=on
text="[Technique][Variables][TEXTE]"
center=true
duration="[Technique][Variables][DUREE]"

A vos Awtrix :slight_smile:

4 « J'aime »

Bonjour,
je suis nouveau sur Awtrix V3.
Tout d’abord, merci pour le partage de ce tuto.
j’essai de comprendre plusieurs choses:

  1. comment mettre à jour une info jeedom automatiquement (j’ai vu le post plus haut mais je ne comprends pas comment faire.
  2. Avec le code fourni, j’arrive à pousser des info vers l’awtrix mais le paramètre « gradient » ne foctionne pas (problème de format de valeur):
    en json ça fonctionne
 {
  "text": "Hello World",
  "gradient": ["#AD0E8D", "#7D00D1"],
  "duration": 10
}
mais avec le bloc code, j'ai un # qui s'ajoute au début et le format n'est pas reconnu
{
[icon] => 46009
[pushIcon] => 2
[scrollSpeed] => 50
[text] => #330#
[center] => 1
[duration] => 20
[rainbow] => 0
[gradient] =>**#**["#FDEE00","#BB0B0B"]
}

d’avance merci

Bonjour,

Il suffit de mettre à jour la commande entrée.

Dans mon exemple [Technique][Variables][TEXTE] c’est une commande info d’un virtuel qui est mis à jour par un scénario avec la commande « event ». Quand je met à jour cette commande info c’est répercuté sur l’Awtrix sans rien faire d’autre :blush:

Je regarde ça en début de semaine. Je n’avais pas testé avec un array comme demandé par la commande « gradient ». Ça ne devrait pas être trop difficile car je vois où est le problème (mon code pense qu’il s’agit d’une commande et rajoute donc le « # »). Peut-être que je devrais par contre changer la façon de rentrer les commandes en tant que paramètres.

Bonjour,

1er post mis à jour pour que tu puisses utiliser la commande gradient.
Attention au formatage du tag (j’ai rajouté un exemple).
Dans ton cas cela sera : gradient:"[#AD0E8D, #7D00D1]"

Le formatage de la commande json_encode m’embête plus qu’autre chose au final. A voir si je n’aurais pas plus intérêt à construire le json « à la main ».

Super merci ça fonctionne par contre ne pas mettre de double quotes autour des valeurs (en gras)

Dans ton cas cela sera : « gradient »: "[#AD0E8D, #7D00D1]"

sinon ça ne fonctionne pas

1 « J'aime »

Bonjour,

Merci pour ton retour.
Tu veut dire comme ça ?

gradient="[#AD0E8D,#7D00D1]"

tout à fait

En effet c’était une coquille dans ma réponse.
L’exemple dans le 1er post est par contre correct.

Amuse-toi bien :blush:

merci
par contre toujours pas pigé pour la mise à jour d’un TAG:
extrait du scénario:

Reprenons de zéro.

Prenons l’exemple :

app=app1
mode=on
text="[Technique][Variables][TEST]"
center=false
duration=20
gradient="[#AD0E8D,#7D00D1]"

[Technique][Variables][TEST] est une commande info d’un virtuel (cela pourrait être une variable également si on voulait) :

Ici sa valeur est « TEST1 ».

Tu passes les tags via un scénario à l’AWTRIX :

L’AWTRIX va alors afficher comme texte « TEST1 » (avec un beau gradient de couleur etc …).
A ce moment, si tu veux alors changer le texte il te suffit juste de changer la valeur de la commande info [Technique][Variables][TEST] du virtuel pour économiser le support mémoire de l’AWTRIX et également éviter qu’il ne bugge si changements trop fréquents.

Tu peux changer la valeur de la commande info du virtuel via scénario (commande « event ») :

Tu peux aussi bien entendu lier ta commande info du virtuel à une mesure de température par exemple, auquel cas il n’y a rien à faire pour rafraîchir l’affichage de l’AWTRIX. Ou rentrer directement dans le tag « text » ton équipement Température sans passer par un virtuel.

du coup, mon équipement qui est reporté dans le tag text (voir ci-dessus), à chaque fois qu’il est mis à jour dans jeedom, il se met à jour sur l’awtrix. Je n’ai rien à faire ou je dois quand même créer le scénario avec comme déclencheur les infos que je veux mettre à jour ?
Désolé pour la compréhension un peu longue…

Ta commande Météo devrait être mise à jour sans rien faire sur l’AWTRIX (c’est jMQTT qui mettra à jour).

Tu peux vérifier dans jMQTT que pour le topic « awtrix_xxxx/custom/App1 » :

  • tu as bien ta commande action jMQTT qui indique le nom de ta commande info Météo
  • que dans la commande info jMQTT tu as bien la valeur de ta commande info Météo

Ne pas oublier de configurer dans la commande jMQTT :

Ainsi, si « Pub. Auto » est bien sélectionné pour la commande jMQTT correspondant à la Custom App

En effet je viens de voir que ça s’est mis à jour tout seul. J’ai bien le « pub.auto » d’activé comme précisé au début du sujet.
Autre question: si je veux faire plusieurs custom app, je dois faire un bloc action avec les tag app1 et le bloc code puis app2 et le bloc code…j’ai peur que les tag se mélangent

En effet tu as vu que je passe les tags différemment de toi pour éviter les mélanges de tag.
Comme ça je peux tout mettre dans 1 scénario de notification, et mon bloc code est dans un autre.

Sinon faire 1 scénario = 1 custom app.

1 « J'aime »

Bon j’ai pigé c’est cool. arrives-tu à passer en text des infos et du texte
du style pour la t°C:
text=in: « [Séjour][Séjour][Température] » °C out: « [Extérieur][Sonde][Température] » °C

C’est pour ce genre de cas que c’est mieux de passer par un virtuel pour créer ton texte à partir de différentes sources :wink:

1 « J'aime »

en effet ça fonctionne bien avec un virtuel.
Merci pour ta patience