Bonjour,
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) :
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