Aller au contenu

Recommended Posts

Pour ceux qui ne connaissent pas le Particle Photon, il s'agit d'une petite carte électronique programmable avec une puce Wifi embarquée. La programmation de la puce se fait avec un IDE en ligne disponible sur le site de Particle et le language est très sensiblement le même que pour les cartes Arduino.

 

L'avantage de cette puce, c'est d'une sa taille (De mémoire ils parlent de 6x plus petites qu'un Arduino), le wifi intégré, et le prix : 19USD hors frais de port et enfin (et surtout), le Particle Cloud !

 

Le Particle Cloud permet a votre puce d'être connecté, consultable et pilotable en tout instant via vos propres requêtes REST.

 

En gros, avec cette puce vous êtes capable de fabriquer n'importe quoi pour votre système domotique et de l'intégrer totalement avec votre HC2. Le tuto qui va suivre portera de manière générique sur la communication bi directionnel entre le Photon et votre HC2. Je publierai plus tard et dans un autre sujet, le code source d'un module permettant d'activer et désactiver l'alarme d'une HC2 avec confirmation d'activation et retour d’échec (avec informations des portes restées ouvertes qui ont causées l’échec). Ce Alarme Button comme je l'ai appelé est basé sur le hardware de l'Internet Button vendu sur le site de Particle (il s'agit d'une puce Photon pluggé sur une carte avec 4 boutons, un accéléromètre et 11 LED RGB disposées en cercle. (Voir Internet Button).

 

 

Communication du HC2 --> Particle Photon :

 

a/ Exécuter quelque chose sur le Particle Photon :

 

 Tout d'abord, il faut déclarer dans le code de votre Photon votre fonction publique (a l'intérieur de votre boucle void setup ) :

void setup() {
Spark.function("NomDeLaFonctionCLOUD", NomDeLaFonctionLOCAL);
}

NomDeLaFonctionCLOUD sera le nom appelé depuis la HC2 (ATTENTION contrairement a mon exemple le nom ici ne doit pas dépasser les 12 caractères)

 

NomDeLaFonctionLOCAL sera le nom de votre fonction exécutée dans le code de votre Photon :

int NomDeLaFonctionLOCAL() {
 // Les trucs a exécuter
}

Et voila, c'est fini du côté de votre Photon.

 

Maintenant, sur votre HC2.

 

A noter que la connexion avec le Photon se fait en https et non http. Ce qui veut dire que la fonction netFhttp n'est pas possible ! Il faut donc utiliser la commande Net.HttpClient qui fonctionne uniquement dans une scène !

Donc exit le code dans un virtual device. A vous de voir comment vous voulez vous y prendre, mais pour ma part, j'ai créer une scène dédiée a la communication avec le Photon. Mes virtuals device ne font que passer 2 arguments dans une variable global, arguments repris par la scène de communication avec le Photon.

 

Donc pour comprendre le schéma, l'appui sur un bouton de mon virtual device, modifie une variable pour contenir le nom de la fonction a exécuter, puis une seconde variable avec un éventuel paramètre. Puis ma scène se déclenche automatiquement, récupère ces deux valeurs pour communiquer avec le photon et réinitialise les variables pour la prochaine utilisation.

 

D'un point de vue authentification sur le Cloud, il vous faut récupérer le N° unique de votre device Photon et le Token d'authentification. 

 

Voici donc le code de ma scène pour gérer l’exécution d'une scene. (Les deux variables globales que j'ai créé auparavant sont donc : IntBut_Function et IntBut_Argument) :

local Device ='xxxxxxxxxxx'
local Token ='xxxxxxxxx'
local FunctionRequested = fibaro:getGlobalValue("IntBut_Function") 
local ArgumentSent = fibaro:getGlobalValue("IntBut_Argument") 


------------------ FONCTION SPARK ------------------
function SparkFunction(Name,Argument)
        local Path = 'https://api.particle.io/v1/devices/'..Device..'/'..Name..'?access_token='..Token        
        local Spark = net.HTTPClient();
        Spark:request(Path, { 
                            options = { 
                                    method = 'POST', 
                                    headers = {["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"}
                                    ,
                                    data = 'arg='..Argument
                                   }
                            ,      
                            success = function(response)
                              if tonumber(response.status) == 200 then
                                print('Function "'..Name..'" ('..Argument..') sent with success');
                                SparkTable = json.decode(response.data)
                              else
                                print('Function "'..Name..'" ('..Argument..') Error Status : '..response.status);
                              end
                            end      
                            ,         
                            error = function(err)
                              print('Connection error = ' .. err)
                            end    
                            });  
end
------------------ FIN DE FONCTION SPARK ------------------


Cette fonction est donc générique pour tous les appels de fonctions. J'ajoute alors a cette scène a la suite, un bout de code comme celui-ci pour chaque fonction :

if FunctionRequested == "NomDeLaFonctionCLOUD" -- Ici il s'agit du nom de la fonction Cloud déclaré précedement dans le code de notre Photon
	then
  	SparkFunction(FunctionRequested, ArgumentSent)
end

PS : J'aurais pu exécuter le code de la fonction en direct sans passer par ce bout de code, mais j'ai fais ce choix afin de pouvoir également exécuter d'autres actions que celle de communiquer avec le Photon.

 

Et enfin pour lancer tout le processus depuis un virtual device ou depuis une scène, il suffit d'intégrer ces deux lignes de codes dans un bouton ou ailleurs :

fibaro:setGlobal("IntBut_Argument",ArgumentATransmetre)
fibaro:setGlobal("IntBut_Function",NomDeLaFonctionCLOUD)

b/ Récupérer la valeur d'une variable contenue dans le Photon :

 

 

Cette fois nous souhaitons récupérer la valeur d'une variable.

 

On déclare une variable public dans le code source du Photon :

//Particle.variable("LaVariableCLOUD", &LaVariableLOCAL, STRING);

Puis dans la HC2, l'approche est exactement la même, mais il faudra tout d'abord créer une autre variable global pour stocker temporairement le nom de la variable demandé et une autre pour stocker le résultat (ex : IntBut_Variable et MaVariableDeResultat). Et voici la fonction a intégrer dans la scène gérant la communication avec le Photon :

local VariableRequested = fibaro:getGlobalValue("IntBut_Variable")


--------------------- VARIABLE SPARK ----------------------
function SparkVariable(Name)
        local Path = 'https://api.particle.io/v1/devices/'..Device..'/'..Name..'?access_token='..Token
        local Spark = net.HTTPClient();
        local Result
        Spark:request(Path, { 
                            options = { 
                                    method = 'GET', 
                                    headers = {["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"}
                                    ,
                                   }
                            ,      
                            success = function(response)
                              if tonumber(response.status) == 200 then
                                print('Variable "'..Name..'" requested with success');
                                SparkTable = json.decode(response.data)
          						Result = SparkTable.result
          						fibaro:setGlobal("MaVariableDeResultat",Result)
                              else
                                print('Function "'..Name..' Error Status : '..response.status);
                              end
                            end      
                            ,         
                            error = function(err)
                              print('Connection error = ' .. err)
                            end    
                            });
end
------------------ FIN DE VARIABLE SPARK ------------------

 

 

Puis le bloc d'appel a ajouter a la suite :

if VariableRequested == "LaVariableCLOUD" -- Ici il s'agit du nom de la variable Cloud déclaré précedement dans le code de notre Photon
    then
    SparkFunction(VariableRequested)
end

et enfin le code a intégrer a un boutton pour autre pour appeler tout le bazard :

fibaro:setGlobal("IntBut_Variable","LaVariableCLOUD")

Communication du Particle Photon --> HC2 :

 

 

Cette fois ce sera beaucoup plus simple. A noter qu'il est possible de modifier la valeur d'une variable via un requete REST mais que cette modification ne déclenche pas une éventuelle scène associée. Je vais alors vous montrer ce qui me semble être la requête la plus utile, a savoir une requête demandant l'appuie sur le bouton d'un Virtual Device :

 

Ici tout ce passe dans le code source du Photon :

 

Comme vous pouvez le voir, il faut renseigner l'adresse IP de la box, votre admin:password en base 64, l'ID du device a actionner et le N° du boutton. Dans mon exemple ci-dessous le Photon demande l'appui sur le bouton 1 du device 50 dès sont initialisation :

String server = "AdresseIPdelaHC2"; // Adresse IP de la box Fibaro
String FibaroLogin = "xxxxxxxxxxx"; // admin:password en base 64
int FibaroDeviceID = 50; // N°ID du device Fibaro a piloter
int NduBoutton = 1; // N° du bouton a actionner

void setup() {

FibaroCommunication("{\"args\":[" + String(NduBoutton) + "]}");

}


void loop() {

}



/////////// FONCTION PRIVE DE COMMUNICATION AVEC LA FIBARO /////////// 
bool FibaroCommunication(String PostData) {

    if (Fibaro.connect(server,80)) {
        Serial.println("Connection Success");
        Fibaro.print("POST /api/devices/");
        Fibaro.print(NduBoutton);
        Fibaro.print("/action/pressButton"); 
        Fibaro.println(" HTTP/1.1");
        Fibaro.print("Host: ");
        Fibaro.println(server);
        Fibaro.print("Authorization: Basic "); 
        Fibaro.println(FibaroLogin);
        Fibaro.print("Content-Length: ");
        Fibaro.println(PostData.length());
        Fibaro.println();
        Fibaro.println(PostData);
        return true;
    } 
    else {
        Serial.println("Connection Failed.");
        return false;
    }
}

Bon voila, c'est terminé ! En espérant avoir été assez clair !

 

Vous verrez on peut faire de vrai merveilles avec ce Photon couplé a notre HC2.

  • Upvote 5

Partager ce message


Lien à poster
Partager sur d’autres sites

Nickel ! Merci pour tout ça, je dois justement me prendre le choux pour domotiser ma clim, ca va permettre de faire avancer mon projet (j'espère) plus rapidement que prévu !  ;)

Partager ce message


Lien à poster
Partager sur d’autres sites

Alors oui effectivement ça peut aider. Je vais essayer également de faire un tuto pour domotiser ses volets Somfy via un Arduino ou Photon et une télécommande d'origine. Le tuto de base n'est pas de moi mais comme je l'ai réalisé il y a peu je peu faire profiter de mon expérience. Tu verras l'approche pourrait effectivement t'intéresser fortement...

Envoyé de mon iPhone en utilisant Tapatalk

Partager ce message


Lien à poster
Partager sur d’autres sites

et dire que je l'ai reçu et qu'il est encore dans sa boite :( mais avec un tuto comme celui là  je vais le sortir vite fait :60:  vivement la suite ...... :2:

Partager ce message


Lien à poster
Partager sur d’autres sites

Je ne connaissais pas . Merci pour le tuto, c'est effectivement très interressant.  :)

Partager ce message


Lien à poster
Partager sur d’autres sites

J'ai apporté quelques modifications je me suis rendu compte qu'une petite erreur de copier/coller s'était glissé dans le tuto.

Partager ce message


Lien à poster
Partager sur d’autres sites

bonjour,

Communication du Particle Photon --> HC2 :

comment remplacer dans ton code le bouton (NduBoutton) par une variable

je souhaite remonter une info vers la hc2 (en renseignant une globalevariable)

est ce possible?

dans ce style:

#define ANEMOMETRE  1   //pin D3, interruption n°1
#define PI        3.1415
#define RAYON     0.10  //rayon en mètre de l'anémomètre en mètre
volatile unsigned int countAnemometre = 0;  

unsigned long previousMillis=   0;
unsigned long previousMillis2=  0;
unsigned long delaiAnemometre = 3000L;    //3 secondes
unsigned long delaiProgramme =  60000L;   //60 sec

float gust(0);        //vent max cumulé sur 1 min
float wind(0);        //vent moyen cumulé sur 1 min
int nbAnemo = 0;      //nb d'occurence de mesure Anemo
float vitesseVent(0); //vent moyen cumulé sur 1 min

#include <Ethernet.h>
#include <SPI.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0E, 0xA5, 0x7E }; //physical mac address 90:A2:DA:0E:A5:7E
byte ip[] = { 192, 168, 1, 175 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask   
IPAddress server(192,168,1,24); //HC2 FIBARO

EthernetClient client;


void setup() {
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  delay(1000);
    attachInterrupt(ANEMOMETRE,interruptAnemometre,RISING) ;
pinMode(13, OUTPUT);
pinMode(3, INPUT);

Serial.println("connecting...");
  String PostData = "{\r\n\"value\":\"'vitesseVent'\"\r\n}"; //JSON data to send
  if (client.connect(server,80)) {
    Serial.println("connected");
    client.print("PUT /api/globalVariables/testvent"); //Fibaro Global Variable
    client.println(" HTTP/1.1");
    client.println("Host: 192.168.1.24");
    client.println("Authorization: Basic XXXXXXXXXXXXXXXXXXXXXXXXx");   //need to insert base 64 user:password
    client.print("Content-Length: ");
    client.println(PostData.length());
    client.println();
    client.println(PostData); 
  }
  else {
   Serial.println("Connection Failed."); 
  }
 
}
/*  *  Fonction d'interruption de l'anémomètre qui incrémente un compteur à chaque impulsion */
void interruptAnemometre(){
  countAnemometre++;
}
void loop(){    
 int BP = digitalRead(3); // Lecture du capteur
if (BP == LOW) {
digitalWrite(13, HIGH); // Allume la Led
}
else {
digitalWrite(13, LOW); // Eteind la Led
} 
  unsigned long currentMillis = millis(); // read time passed
//Récupération des infos de l'anémomètre toutes les 3 sec
  //Enregistrement cumulé des valeurs
  if (currentMillis - previousMillis > delaiAnemometre){
    previousMillis = millis();
   // vitesseVent = (PI * RAYON * 2 * countAnemometre)/3*3.6; //3 = durée de prise de mesure (3sec)
    vitesseVent = (0.83 * countAnemometre)/3*3.6; //3 = durée de prise de mesure (3sec) 
    if(vitesseVent>gust) gust = vitesseVent;
    wind += vitesseVent;
    nbAnemo++;
    countAnemometre = 0;
    Serial.print("Vent:");
    Serial.println(vitesseVent); 
       
  }
  //Toutes les minutes, compilation des valeurs et envoi au serveur  
  if (currentMillis - previousMillis2 > delaiProgramme){
    previousMillis2 = millis();
    float avgwind = wind / nbAnemo;
    
    Serial.print("Wind AVG : ");
    Serial.println(avgwind);
    Serial.print("Gust : ");
    Serial.println(gust);
    
    //RAZ des compteurs qui ont servi a calculé les valeurs moyennes sur 1 min
    wind = 0;
    gust = 0;
    nbAnemo = 0;
  }
   if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
      ;
  }
}

 

Modifié par flamalex

Partager ce message


Lien à poster
Partager sur d’autres sites

×