février 23

Domotique avec Google Home, Teensy et Blynk

Mon projet domotique 2017. Le but étant de piloter les télécommandes infra-rouge (Freebox, ampli 5.1, switch HDMI…), les lampes de la maison (via des prises commandés en 433mhz) et un ruban LED multicolors via mon Google Home (et aussi IFTTT et Blynk).
Tout le montage rentre dans un bocal translucide de chez Ikea.

Le tout consomme 1.7 Watts au repos et 6.5 Watts avec une couleur allumé.

 

Pré-requis

Composants :

  • Régulateur 3.3volts LD1117v33
  • Teensy 3.2
  • ESP01 (WiFi)
  • XY-FST-433 (RX433)
  • SFH4346 (LED infra-rouge)
  • WS2812 (ruban LED)
  • Condensateur 1000 uF/25V
  • Transfo 5 Volts /2A
  • Éventuellement, un relais 220V/RX433

Le Principe

IFTTT reçoit les commandes du Google Home (trigger) et l’envoie une URL (WebHook) sur le serveur Blynk.
Celui-ci est connecté au Teensy via le ESP01 et déclenche des actions via le code Arduino.

On dit : Allume et un mot clé (tout, un, deux, Freebox…), le code Arduino contient des IF qui réagissent aux mot clés indiqués et envoie les codes infra-rouge ou 433mhz.

Le code Arduino

/*URL pour webhook IFTTT (passé en GET)  
 * https://ipduserveurblynk:9443/tokenblynk/update/v2?value={{TextField}}
 * avec le navigateur
 * https://ipduserveurblynk:9443/tokenblynk/update/v0?value=MotClé 
 * 
 * A base de Teensy 3.2
 * 2017 - Par Pit Wyman
 */
 
#define ESP8266_BAUD vitesse
#include <SoftwareSerial.h>
#define HWSERIAL Serial1 //pin RX1=0, TX1=1 du TeensyLC, Teensy 3.2

//RX433
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
int PinRX433 = 10; //pin Arduino/Teensy du module RX433

//Blynk
#define BLYNK_PRINT Serial //pour afficher les infos de connexion Wifi et Blynk  
#include <BlynkSimpleShieldEsp8266.h>

//ESP10
#include <ESP8266_Lib.h>
SoftwareSerial EspSerial(0, 1); // TX, RX de ESP10
ESP8266 wifi(&EspSerial);

//InfraRouge
/*
2 LED IR en série et Pas de résistance (avec certaines alims, ça envoie pas assez de jus)
Arduino Uno/Nano = pin 3
Teensy LC = 16
Tensy 3 à 3.6 = pin 5
*/
#include <IRremote.h>
//irrecv.blink13(true);// allume la LED interne du Teensy lors de l'envoie
IRsend irsend; //LED IR

//Ruban LED WS2812
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define WS2812Data 16 // Pin de la broche data du WS2812

// nombre de LED du WS2812
#define NbLED 55
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NbLED, WS2812Data, NEO_GRB + NEO_KHZ800);

int vitesse = 9600;
char auth[] = "***"; //token Blynk
char ssid[] = "****"; // Nom WiFi
char pass[] = "*****"; // Clé WiFi

#define VERSION "MaDomotique - Fin 2017"

void setup() {/*******************************************/
  Serial.begin(vitesse);//moniteur serie
  pixels.begin(); // NeoPixel library.
 //transmission RX433
  mySwitch.enableTransmit(PinRX433);
  // Optional set pulse length. default 320
  //mySwitch.setPulseLength(280); 
  // Optional set protocol (default is 1, will work for most outlets)
  //mySwitch.setProtocol(1); 
  // Optional set number of transmission repetitions. defaut 15
  //mySwitch.setRepeatTransmit(15);

  EspSerial.begin(ESP8266_BAUD);
  delay(50);
  Blynk.begin(auth, wifi, ssid, pass, "192.168.0.30"); //IP du serveur local Blynk
  
ws2812 (0,NbLED, 0,0,0);//éteint
ws2812 (0,NbLED, 255,255,255);//allume
delay(200);
ws2812 (0,NbLED, 0,0,0);//éteint
}

/******************** Allumer/éteindre lampes, Freebox ou Ampli 5.1 ***********************************/

BLYNK_WRITE(V0){// Allume ***
String ValeurV0 = param.asStr();
Serial.print("allume : ");
Serial.println(ValeurV0);

ws2812 (0,8, 255,0,0);//controle
ws2812 (0,8, 0,0,0);
   
Blynk.virtualWrite(0,ValeurV0);//envoie la valeur sur display de Blynk
 
      if (ValeurV0 == "tout" or ValeurV0 == "tous" or ValeurV0 == "tu"){
      mySwitch.send(16762196, 24); //lampe 1
      delay(100);
      mySwitch.send(16765268, 24); //lampe 2
      delay(100);
      mySwitch.send(16766036, 24); //lampe 3 
      delay(100);
      mySwitch.send(16766228, 24); //étoile papier
      delay(100);
      ws2812 (0,NbLED, 255,0,0); //WS2812 en rouge
      }

  if (ValeurV0 == "première" || ValeurV0 == "un" || ValeurV0 == "1" || ValeurV0 == "hein"){
  mySwitch.send(16762196, 24); //lampe 1
  }

      if (ValeurV0 == "deuxième" || ValeurV0 == "deux" || ValeurV0 == "2" || ValeurV0 == "de"){
      mySwitch.send(16765268, 24); //lampe 2
      }

  if (ValeurV0 == "troisième" || ValeurV0 == "trois" || ValeurV0 == "3"){
  mySwitch.send(16766036, 24); //lampe 3 
  }

  if (ValeurV0 == "veilleuse" or ValeurV0 == "étoile"){
  mySwitch.send(16766228, 24); //étoile papier
  }

  if (ValeurV0 == "cuisine") {
  mySwitch.send(1975778, 24); //cuisine
  }

      if (ValeurV0 == "Freebox" or ValeurV0 == "télé" or ValeurV0 == "tele"){

      irsend.sendNEC(0xA55A38C7, 32);// InfraRouge - Ampli 5.1 sur ON (allume la télé via prise intélligente)
          
      irsend.sendNEC(0xFF20DF, 32);// InfraRouge - switch HDMI sur Freebox
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);
      delay(100);
         
      CommandeFreebox("power");// allume la Freebox
      delay(2000);// attendre 2 sec
      CommandeFreebox ("ok");// valider (sur bouton télévision)
      }

if (ValeurV0 == "ampli" or ValeurV0 == "l'ampli"){// Ampli 5.1
      irsend.sendNEC(0xA55A38C7, 32);
}

if (ValeurV0 == "blanc"){// Ruban LED
      ws2812 (0,NbLED, 255,255,255);
}
if (ValeurV0 == "rouge"){// Ruban LED
      ws2812 (0,NbLED, 255,0,0);
} 
if (ValeurV0 == "vert"){// Ruban LED
      ws2812 (0,NbLED, 0,255,0);
} 
if (ValeurV0 == "bleu"){// Ruban LED
      ws2812 (0,NbLED, 0,0,255);
}
if (ValeurV0 == "jaune"){// Ruban LED
      ws2812 (0,NbLED, 255,255,0);
}
if (ValeurV0 == "orange"){// Ruban LED
      ws2812 (0,NbLED, 255,127,0);
}
if (ValeurV0 == "violet"){// Ruban LED
      ws2812 (0,NbLED, 127,0,255);
}

}//V0

BLYNK_WRITE(V1){// éteint ***
String ValeurV1 = param.asStr();
Serial.print("éteint : ");
Serial.println(ValeurV1);

ws2812 (0,8, 255,0,0);//controle
ws2812 (0,8, 0,0,0);
 
  if (ValeurV1 == "tout" or ValeurV1 == "tous" or ValeurV1 == "tu"){
  mySwitch.send(16762193, 24); //lampe 1
  delay(100);
  mySwitch.send(16765265, 24); //lampe 2
  delay(100);
  mySwitch.send(16766033, 24); //lampe 3 
  delay(100); 
  mySwitch.send(16766225, 24); //étoile papier
  delay(100);
  ws2812 (0,NbLED, 0,0,0); //WS2812
  }
  
      if (ValeurV1 == "première" || ValeurV1 == "un" || ValeurV1 == "1" || ValeurV1 == "hein"){
      mySwitch.send(16762193, 24); //lampe 1
      }

  if (ValeurV1 == "deuxième" || ValeurV1 == "deux" || ValeurV1 == "2" || ValeurV1 == "de"){
  mySwitch.send(16765265, 24); //lampe 2
  delay(100);
  }

      if (ValeurV1 == "troisième" || ValeurV1 == "trois" || ValeurV1 == "3"){
      mySwitch.send(16766033, 24); //lampe 3 
      delay(100);
      }

  if (ValeurV1 == "veilleuse" or ValeurV1 == "étoile"){
  mySwitch.send(16766225, 24); //étoile papier
  }

  if (ValeurV1 == "cuisine"){
  mySwitch.send(1975778, 24); //cuisine
  }
  
  if (ValeurV1 == "Freebox" or ValeurV1 == "télé"){
  CommandeFreebox ("power");// éteint la Freebox

  //la télé est éteinte via l'ampli HDMI
  //irsend.sendNEC(0x2FD48B7, 32);// InfraRouge - TV Toshiba sur OFF
  //delay(40);
  //irsend.sendNEC(0xFFFFFF, 32);
  delay(100);
  irsend.sendNEC(0xA55A38C7, 32);// InfraRouge - Ampli 5.1 sur OFF 
  }
  
      if (ValeurV1 == "ampli" or ValeurV1 == "l'ampli"){// Ampli 5.1
      irsend.sendNEC(0xA55A38C7, 32);
      }
      
if (ValeurV1 == "blanc" or ValeurV1 == "rouge" or ValeurV1 == "vert" or ValeurV1 == "bleu" or ValeurV1 == "jaune" or ValeurV1 == "orange" or ValeurV1 == "violet"){// Ruban LED
      ws2812 (0,NbLED, 0,0,0);
} 

}//V1

/****************************************** Switch HDMI  - InfraRouge *********************************/
BLYNK_WRITE(V2){// HDMI ***
String ValeurV2 = param.asStr();
Serial.print("HDMI  : ");
Serial.println(ValeurV2);

if (ValeurV2 == "Freebox"){
      irsend.sendNEC(0xFF20DF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32); 
  }//if

  if (ValeurV2 == "Netflix"){
      irsend.sendNEC(0xFF10EF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);
  }//if

  if (ValeurV2 == "Kodi" or ValeurV2 == "mediacenter" or ValeurV2 == "libreelec"){
      irsend.sendNEC(0xFF50AF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);  
  }//if

}//V2

/************************************* Ampli 5.1  - InfraRouge ************************************/
BLYNK_WRITE(V3){// monte/augmente l'ampli de ***
int ValeurV3 = param.asInt();
Serial.print("monte le volume de : ");
Serial.println(ValeurV3);

ws2812 (8,8+ValeurV3, 255,0,0);//controle
ws2812 (8,8+ValeurV3, 0,0,0);

  if (ValeurV3){
  
for (int i=0; i <= ValeurV3*2; i++){
Serial.println(ValeurV3);  
irsend.sendNEC(0xA55A50AF, 32);
delay(40);  
}//for
  }//if
  
}//V3

BLYNK_WRITE(V4){// baisse/diminue l'ampli de ***
int ValeurV4 = param.asInt();
Serial.print("baisse le volume de : ");
Serial.println(ValeurV4); 

ws2812 (8,8+ValeurV4, 255,0,0);//controle
ws2812 (8,8+ValeurV4, 0,0,0);

   if (ValeurV4){
  
for (int i=0; i <= ValeurV4*2; i++)
{
Serial.println(ValeurV4);  
irsend.sendNEC(0xA55AD02F, 32);
delay(40);
}//for
  }//if
  
}//V4

BLYNK_WRITE(V5){// coupe/remet l'ampli
int ValeurV5 = param.asInt();

if (ValeurV5 == 1){
Serial.println(ValeurV5);  
irsend.sendNEC(0xA55A48B7, 32);
  }//if
  
}//V5

/***************************************** Chaines Freebox - Webhook ************************/

BLYNK_WRITE(V6){// Freebox/regarder ***
String ValeurV6 = param.asStr();
Serial.print("regarder : ");
Serial.println(ValeurV6);

//définition des chaines
if (ValeurV6=="Mosaïque" or ValeurV6=="mosaïque" or ValeurV6=="panel") {CommandeFreebox("0");}
if (ValeurV6 == "TF 1") {CommandeFreebox("1");}
if (ValeurV6 == "France 2") {CommandeFreebox("2");}
if (ValeurV6== "France 3") {CommandeFreebox("3");}
if (ValeurV6 == "Canal +" or ValeurV6=="Canal") {CommandeFreebox("4");}
if (ValeurV6 == "France 5") {CommandeFreebox("5");}
if (ValeurV6 == "M 6") {CommandeFreebox("6");}
if (ValeurV6=="Arte") {CommandeFreebox("7");}
if (ValeurV6=="C 8") {CommandeFreebox("8");}
if (ValeurV6=="W 9") {CommandeFreebox("9");}
//a partir de 2 chiffres, ça ne marche plus ?!?


if (ValeurV6=="pause") {CommandeFreebox("play");}
if (ValeurV6=="direct") {
CommandeFreebox("green");
delay(2000);
CommandeFreebox("ok");
}

if (ValeurV6=="programme") {CommandeFreebox("epg");}
if (ValeurV6=="menu") {CommandeFreebox("green");}
if (ValeurV6=="maison") {CommandeFreebox("home");}
if (ValeurV6=="ok") {CommandeFreebox("ok");}
if (ValeurV6=="haut") {CommandeFreebox("up");}
if (ValeurV6=="bas") {CommandeFreebox("down");}
if (ValeurV6=="droite") {CommandeFreebox("right");}
if (ValeurV6=="gauche") {CommandeFreebox("left");}

if (ValeurV6=="dvd"){
CommandeFreebox("home");
delay(2000);
CommandeFreebox("right");
delay(1000);
CommandeFreebox("right");
delay(1000);
CommandeFreebox("right");
delay(1000);
CommandeFreebox("ok");
}

if (ValeurV6=="TV"){
CommandeFreebox("home");
delay(2500);
CommandeFreebox("ok");
}

/*************************************** Regarder Freebox Netflix ou Kodi ***************************************/

if (ValeurV6 == "Freebox" or ValeurV6 == "télé"){
      irsend.sendNEC(0xFF20DF, 32);// InfraRouge - switch HDMI sur Freebox
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);
      //la télé est allumé via l'ampli HDMI
      //delay(100);
      //irsend.sendNEC(0x2FD48B7, 32);// InfraRouge - TV Toshiba sur ON
      //delay(40);
      //irsend.sendNEC(0xFFFFFF, 32);
      delay(100);
      irsend.sendNEC(0xA55A38C7, 32);// InfraRouge - Ampli 5.1 sur ON     
  
      CommandeFreebox("power");// allume la Freebox
      delay(2000);// attendre 2 sec
      CommandeFreebox ("ok");// valider (sur bouton télévision)
      }

if (ValeurV6 == "Netflix"){
      //Ampli (qui allume la télé)
      irsend.sendNEC(0xFF10EF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);  
delay(100);
      //HDMI sur Netflix
      irsend.sendNEC(0xFF10EF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32); 
}
if (ValeurV6 == "Kodi"){
      //Ampli (qui allume la télé)
      irsend.sendNEC(0xFF10EF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);  
delay(100);
      //HDMI sur Kodi
      irsend.sendNEC(0xFF50AF, 32);
      delay(40);
      irsend.sendNEC(0xFFFFFF, 32);
}

}//V6

/********************************************* couper les lumières et la télé ***********************/

BLYNK_WRITE(V7){// on va se coucher
int ValeurV7 = param.asInt();

if (ValeurV7){
// lumières
mySwitch.send(16762193, 24); //lampe 1
  delay(100);
  mySwitch.send(16765265, 24); //lampe 2
  delay(100);
  mySwitch.send(16766033, 24); //lampe 3 
  delay(100); 
  mySwitch.send(16766225, 24); //étoile papier
  delay(100);
  ws2812 (0,NbLED, 0,0,0); //WS2812

CommandeFreebox ("power");// éteint la Freebox

irsend.sendNEC(0xA55A38C7, 32);// éteint l'ampli (qui éteint la télé)    
}
  
}//V7

/****************************** Ruban LED WS 2812 via l'appli Blynk *****************************/

BLYNK_WRITE(V8){ //zeRGBa de Blynk (http://docs.blynk.cc/#widgets-controllers-zergba)
  
  int r = param[0].asInt(); //rouge
  int v = param[1].asInt(); //vert
  int b = param[2].asInt(); //bleu

ws2812 (0,NbLED, r,v,b);//WS2812

}//V8


void CommandeFreebox(String MotCle){ /************************************* Fonction envoie des codes Freebox **************************************/
// WebHook Blynk avec : http://hd1.freebox.fr/pub/remote_control?code=86700567&key=/pin/
//&key=<touche>&long=true
//&key=<touche>&repeat=<n>

Blynk.virtualWrite(10, MotCle);
}

void ws2812 (int debut, int fin, int rouge, int vert, int bleu) /************** Fonction d'affichage des LED du ruban WS2812 *****************************/
{
    for(int i=debut;i<=fin;i++){
    // position de la LED (0=1er), couleurs RVB (de 0 à 255)
    pixels.setPixelColor(i, pixels.Color(rouge,vert,bleu)); 
    pixels.show(); // update couleurs
  }  
}//WS2812


void loop() { /**************************** LOOP *************************/
Blynk.run();      
}//loop


Ce code sera évidement adapté pour votre cas. Pour le miens, lorsque mon ampli 5.1 s’allume, il commande une multiprise « intelligente » qui allume la télé, le caisson basse et autre.
Le seul truc que je n’ai pas pu faire c’est changer les chaines de la Freebox qui ont 2 chiffres. Même en testant une URL dédié à ça, pas moyen.

L’électronique

Je suis partie d’un Teensy 3.2, un Arduino Uno n’est pas suffisant en terme de puissance.

Un ESP01 relié l’ensemble au WiFi, le module RX4333 envoie les codes en 433 mhz. 2 LED infra-rouge relié en série envoient les codes infra-rouge.
Le ruban LED (WS2812) est aussi relié au 5 volts.

L’ensemble est alimenté via un transfo 5 volts, un régulateur 3.3 volts alimente le ESP01. Un condensateur de 1000 uF/25V stabilise la tension (et pour protéger le ruban LED).

Le montage

Les composants électroniques sont fixés sur une plaque et reliés entrent eux par le dessous. Simple mais suffisant.
Le ruban LED s’enroule autour des montants.

J’ai fais une armature avec mon imprimante 3D. Tout est juste emboité, un trou est prévu à la base pour mettre un connecteur pour le transfo.
L’ensemble est coiffé par un bocal (à sucre je crois) de chez Ikea.

Fichier 3D

IFTTT et Blynk

J’utilise aussi le WebHook de IFTTT pour envoyer les mots clés qui seront reçu par Blynk et le WebHook de Blynk pour envoyer du code sur Teensy.

EX : Envoie le mot clé (TextField) sur l’IP du serveur Blynk/LeTokenBlynk, sur la VirtualPin V0

Dans le code Arduino :

BLYNK_WRITE(V0)
String ValeurV0 = param.asStr() (si c’est un mot)
String ValeurV0 = param.asInt() (si c’est un chiffre)

 

source 01 

Catégorie : Electronique | Commenter
février 18

Le Teensy en WiFi avec ESP01

Faire communiquer le Teensy en WiFi est simple et pas chère avec ESP01.
Il faut juste au préalable le configurer et terme de vitesse, mode serveur/client et bien sur nom et clé WiFi, via une liaison série.

le Teensy est alimenté en 5 Volts mais le esp01 à besoin de 3.3 Volts. Cependant, même si le Teensy dispose d’une sortie 3.3 volts, elle est limité à 100 mA, insuffisant pour le ESP01. On doit donc utiliser un régulateur 3.3 Volts.

 

ATTENTION : bien couper le strap situé sous le Teensy car il sera alimenté via la pin Vin et pas via la prise USB

Le code Arduino

Permettant envoyer/recevoir des commande AT, et donc de programmer le ESP01

/*
0 (RX) Arduino ou Teensy sur TX ESP01
1 (TX) Arduino ou Teensy sur RX ESP01

(attention un copier/coller dans le moniteur serie ajoute un espace à la fin des commandes !)

la commande  AT renvoie OK et la LED bleu de EPS01 s'allume brievement
(Si pas de retour, changer la vitesse à 115200)

vitesse de la liaison
AT+CIOBAUD=9600

ResetESP10
AT+RST

Configurer en mode client et serveur
AT+CWMODE=3

Afficher les réseaux WiFi
AT+CWLAP

Connecter au WiFi
AT+CWJAP="nom_ssid","clé_wifi"

Afficher son adresse IP (la 1er est le serveur et la 2e le client)
AT+CIFSR (serveur = 192.168.4.1 - client=192.168.0.32)

AT+GMR
Afficher la version du firmware

 */
int vitesse = 9600; // Use baud rate 115200 during firmware update
void setup() {

    // du moniteur serie vers Arduino/Teensy
    Serial.begin(vitesse);

    // Arduino/Teensy vers ESP01
    Serial1.begin(vitesse);

}

void loop() {

    // ESP01 vers serie
    if ( Serial1.available() ) {
        Serial.write( Serial1.read() );
    }

    // Send bytes from computer back to ESP8266
    if ( Serial.available() ) {
        Serial1.write( Serial.read() );
    }

}

Et donc, en rajoutant du code, on peut facilement contrôler le Teensy via WiFi !

//série

#define ESP8266_BAUD 9600

#include <SoftwareSerial.h>

#define HWSERIAL Serial1 //pin RX1=0, TX1=1 du TeensyLC, Teensy 3.2


//ESP10

#include <ESP8266_Lib.h>

SoftwareSerial EspSerial(0, 1);

ESP8266 wifi(&EspSerial);

Catégorie : Teensy/Arduino | Commenter
juillet 30

Récupérer la valeur MIDI du volume

Un croquis permettant de récupérer la valeur MIDI du curseur de volume de Ableton Live et de l’envoyer, via USB/MIDI, sur un Teensy 3.

A noter que, à chaque changement de set Live, la valeur du volume est automatiquement envoyé !

void setup()
{

}

void loop()
{
int ControleChange, valeur;
  if (usbMIDI.read()) 
  {      // si il y a des messages MIDI
      int ControleChange = usbMIDI.getData1();
      int valeur = usbMIDI.getData2();
    Serial.print("Control change: ");
    Serial.println(ControleChange);   
    Serial.print("Valeur: ");
    Serial.println(valeur);
  }

}//loop
Catégorie : Teensy/Arduino | Commenter
juillet 19

Envoyer plusieurs données entre Teensy et Xbee

J’avais déjà indiqué comment envoyer une donnée à la fois (en faite un byte à la fois) pour commander en ON/OFF une LED par exemple MAIS si l’on souhaite envoyer plusieurs données en série du style :  Si j’envoie la lettre A alors les 3 données suivantes concerne le groupe A,  ça se complique.

J’ai essayé via la library fournis par Xbee mais je n’arrive à rien !

Le code émetteur

/* testé sur Teensy 3.1 et Xbee série 1.
#define HWSERIAL Serial2 //TX2 pin10


void setup() {/********************** SETUP *****************************/
  HWSERIAL.begin(9600);
}

void loop() {
  
  HWSERIAL.write('a');
  HWSERIAL.write(1);
  HWSERIAL.write(2);
  HWSERIAL.write(3);
  delay(1000);
  
   HWSERIAL.write('b');
  HWSERIAL.write(10);
  HWSERIAL.write(20);
  HWSERIAL.write(30);
  delay(1000);
}//loop

Le code récepteur

/* testé sur Teensy 3.1 
on envoie via serie un write(a ou b), si il est reçu, on reçoit les 3 données suivantes.
*/
#define HWSERIAL Serial1

byte DataSerie[4];
byte InSerie;

void setup(){
   HWSERIAL.begin(9600);
 
}


void loop(){
 while (HWSERIAL.available())
{// on place les 4 bytes reçu dans un tableau

      for (int i=0; i<=3; i++)
      {
byte InSerie = HWSERIAL.read();  
DataSerie[i] = InSerie;
      }//for
if (DataSerie[0] == 'a')// le premier byte envoyé doit être le caractère a 
{
 Serial.println("bien recu a"); 
 Serial.println(byte(DataSerie[1]));
  Serial.println(byte(DataSerie[2]));
   Serial.println(byte(DataSerie[3]));
}
if (DataSerie[0] == 'b')
{
 Serial.println("bien recu b"); 
 Serial.println(byte(DataSerie[1]));
  Serial.println(byte(DataSerie[2]));
   Serial.println(byte(DataSerie[3]));  
}
}//while
}//loop

J’ai délibérément fait simple mais c’est une base pour faire des trucs sympa !

Autre façon de faire

Catégorie : Teensy/Arduino | Commenter
juillet 13

Modification de variable via une liaison série

J’ai fais un montage avec Teensy et Xee permettant à 1 bouton de dire via une liaison série :  si je suis appuyé, la variable MaVariable = 1, sinon MaVariable = 0.

J’ai donc : appuie bouton = envoie série de « on », si pas d’appuie = envoie série de « off ». Problème, au repos, j’envoie sans arret le code « off » ce qui est pas top en terme de gestion de l’énergie.

Je pourrais faire, sur la partie réception : si j’envoie autre chose que « on », alors on considère que c’est « off ».
Le truc est que en même temps, j’envoie d’autres code en série, donc cette solution ne tient pas.

J’ai trouvé l’astuce en jouant sur un compteur.

Si le bouton sur OFF, je compte jusqu’à 3 MAIS SEULEMENT à 2, j’envoie le code série « off ». Le compteur reste bloqué à 3 (donc plus d’envoie série) jusqu’à que je bouton soit « on », quand i l’est, l’incrément du compteur se remet sur 1 et attend donc que le bouton soit « off » pour recompter.

Je ne mat pas le code qui fait : si tu appuie, fait : HWSERIAL.write(« on »);

if(Bouton == 1) // si le bouton est ON, on met le compteur = 1
{
  ComptBouton = 1;
  }
if (Bouton == 0 && ComptBouton <=3)//quand le bouton est OFF, on compte jusqu'à 3
{
for (ComptBouton = 1; ComptBouton <=3; ComptBouton++)
{
if(ComptBouton == 2)// à 2, on envoie le code off
{
HWSERIAL.write("off"); 
}//if
}//for
}//if bouton

Comme j’ai galéré un moment sur ça, je partage !

Catégorie : Teensy/Arduino | Commenter
juillet 9

Volume MIDI via liaison série

Le Teensy 3.1 est reconnu nativement comme un périphérique compatible MIDI et il permet aussi de créer des touches à effleurement (capacitive).
Le Xbee (serie 1) est très simple à configurer, voila de quoi faire une belle télécommande audio.

Code émetteur

/* testé sur Teensy 3.1 :
Un les touches à effleurement incrémentent ou décrémentent une valeur de volume (0 à 127).
Un appuie sur une des deux touches envoie via serie, la lettre 'v' qui indique au récepteur que l'on envoie une valeur de volume.
Ensuite, on evoie la valeur de volume. */

#define HWSERIAL Serial2 //TX2 - pin 8
#include <CapacitiveSensor.h>

/*VOLUME*/
int TestBouton10;
int EtatBouton10;
int TestBouton11;
int EtatBouton11;
int ValeurVolume;
/* au changement de set Ableton, à la 1er impulsion des boutons, le volume se met une fraction de seconde au volume du set précédent (ComptVolume part de la dernière valeur) */
const int latenceVolume = 10; // vitesse du curseur
const int MaxHaut = 127; //127 en MIDI

/* TOUCHE SENSITIVE */
int BoutonCommun = 14; // pin commune
int NBtestBoutons = 30; // nombres de test des boutons
int ValCapacitive = 2000; // valeur de l'entrée capacitive

//VOLUME
CapacitiveSensor   Bouton10 = CapacitiveSensor(BoutonCommun, 32); // Volume + (pin 32)
CapacitiveSensor   Bouton11 = CapacitiveSensor(BoutonCommun, 33); // Volume - (pin 33)

void setup() {/********************** SETUP *****************************/
  HWSERIAL.begin(9600); 
}

void loop() {

  //VOLUME
  long TestBouton10 =  Bouton10.capacitiveSensor(NBtestBoutons);
  long TestBouton11 =  Bouton11.capacitiveSensor(NBtestBoutons);

   /**************************************************************** ENVOIE SERIE - VOLUME */
  if (TestBouton10 > ValCapacitive && ValeurVolume < MaxHaut)
  {
       HWSERIAL.write('v');
        ValeurVolume++;
HWSERIAL.write(ValeurVolume);
    delay(latenceVolume);
  }

  if (TestBouton11 > ValCapacitive && ValeurVolume > 0)
  {    
   HWSERIAL.write('v'); 
      ValeurVolume--;
HWSERIAL.write(ValeurVolume);
    delay(latenceVolume);
  }
Serial.println(ValeurVolume);
}//loop

Code récepteur

/* testé sur Teensy 3.1 
on envoie via serie un write('v') et ensuite un write avec une valeur numérique.
si le a est reçu, alors on affiche la valeur numérisue.
*/
#define HWSERIAL Serial1

byte DataSerie[1]; //tableau de 2 valeurs (0 et 1)
byte InSerie;
int i;

void setup(){
   HWSERIAL.begin(9600);
 
}


void loop(){
 while (HWSERIAL.available())
{// on place les 2 byte recu dans un tableau
i = 0;
      for (i=0; i<=2; i++)
      {
byte InSerie = HWSERIAL.read();  
DataSerie[i] = InSerie;

if (char(DataSerie[0]) == 'v')// le premier byte envoyé doit être le caractère v 
{
 Serial.println("bien recu v"); 
 int ValeurVolume = byte(DataSerie[1]);
 usbMIDI.sendControlChange(12, ValeurVolume, 1); //ProgramChange 12, canal MIDI 1
 Serial.println(ValeurVolume );
}
      }//for
      i = 0;
}//while
 
          }//loop



Limitation

Si on envoie d’autre données série en même temps, cela perturbe  le système, les autres données s’intercalant entre la lettre déclencheur ‘v’ et la valeur du volume.
L’idéal serait d’envoyer une seule donnée du style V+ValeurVolume et de découper ensuite en 2 dans la partie récepteur.

 

Catégorie : Teensy/Arduino | Commenter
juin 8

Envoyer une donnée entre Teensy et Xbee

Le pitch étant d’envoyer une phrase, ou une variable, entre 2 Teensy 3.1, relié chacun à un Xbee serie 1.

La connexion

  • 1 = 3.3 Volt –> vers pin 3.3 Volts du Teensy
  • 2 = Digital OUT —> vers pin 0 (RX1) du Teensy
  • 3 = Digital IN —> vers pin 1 (TX1) du Teensy
  • 10 = GND –> vers pin GND du Teensy

xbee-pins teensy31_front_pinout

 

Pour ma part, je n’ai pas eu besoin de programmer quoi que ce soit sur les Xbee.
J’ai un couple Teensy/Xbee sur mon PC fixe et un autre couple sur mon portable.

La programmation

J’ai vu beaucoup d’exemples divers de sketch Arduino ou Teensy, vers comme souvent, les gens n’indique pas la version de leur matos. Donc, j’ai fais ma petite sauce, qui fonctionne sur Teensy 3.1.

Envoie

/* Testé sur Teensy 3.1 */ 
#define HWSERIAL Serial1 // pin 0 et 1
void setup() {
HWSERIAL.begin(9600);
}
void loop() {
HWSERIAL.println("Hello"); //ln pour avoir un retour à la ligne après "hello"
delay(500);
}

Réception

/* Testé sur Teensy 3.1 et Xbee serie 1 */
#define HWSERIAL Serial1

void setup() {
HWSERIAL.begin(9600);
}
 
void loop() {
if (HWSERIAL.available())// si des données sont présentes
{
Serial.print(char(HWSERIAL.read())); // char ) caractère, rien ou int = code ASCII
} 
}//loop

 

Dans la console moniteur serie du récepteur, on récupère le mot ou la phrase envoyé.

OK mais le top c’est que ça serve à quelque chose. On va donc tacher d’envoyer une variable précise qui va déclencher l’allumage de la LED interne du Teensy.

/* Testé sur Teensy 3.1 et Xbee serie 1.
Xbee sur pin 0 et 1 du Teensy */
#define HWSERIAL Serial1
byte InSerie;

void setup() {
HWSERIAL.begin(9600);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
}
 
void loop() {

if (HWSERIAL.available())
{
byte InSerie = HWSERIAL.read();
Serial.println(InSerie);
if (InSerie == 'A')
{
Serial.print("recu");// pour vérification
digitalWrite(13, HIGH);
}
else
{
digitalWrite(13, LOW);  
}
}
}//loop

Amélioration

La fonction Print est plus dédié à l’affichage dans une console ou un afficheur LCD, lisible pour un humain.

Dans mon cas, je souhaite envoyer des valeurs, parfois sur plusieurs chiffres. dans ce cas, la fonction write et byte est préférable.

Envoie

#define HWSERIAL Serial1

void setup() {
HWSERIAL.begin(9600); 
}

void loop() {
HWSERIAL.write(1);
delay(1000);
HWSERIAL.write(0);
delay(1000);
}//loop

Réception

#define HWSERIAL Serial1
byte InSerie;

void setup() {
HWSERIAL.begin(9600);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
}
 
void loop() {

if (HWSERIAL.available()>0)
{
InSerie = HWSERIAL.read();
Serial.println(byte(InSerie) );
if (InSerie == 1)
{
digitalWrite(13, HIGH);
}
if (InSerie == 0)
{
digitalWrite(13, LOW); 
}
}
}//loop

La pour le coup, on peut commencer à vraiment commander des trucs entre les 2 teensy.

Notes sur la liaison série

Le protocole série n’envoie par des lettres et/ou des symboles mais des nombres, du code  binaire, hexadécimal… qui sont en correspondance.

Selon ce tableau, faire un Serial.write(‘a’); et Serial.write(97);  (97 en décimal = ‘a’) enverra le même code. On ne peux pas dire au Teensy de faire : si tu reçois ‘a’, fait ça et si tu reçois 97 fait ça; L’action sera la même.

Catégorie : Teensy/Arduino | Commenter
avril 24

Touche sensitive avec Teensy

Le Teensy permet de créer des touches dites sensitives (ou capacitives), cad qui détecte la présence, plus ou moins près selon le type de capteur et le réglages, d’une main ou d’un doigt.

Ce qui est cool, mais pas du tout indiqué sur leur site (qui est une horreur), c’est que selon les versions, des différences existes.

Avant la version 3

Avant la version 3, on devait utiliser une librairy à inclure au code et rajouter une résistance par entrée.

Le principe

Le corps humain peut être considéré comme un condensateur naturel, par rapport à la terre (masse). Avec une certaine valeur de résistance et une feuille d’aluminium au bout du fil, le capteur va commencer à sentir l’approche du doigt ou de la main

teensy-capacitive01

 

Le but du jeux consiste à connecter une résistance entre 2 borne du Teensy et de charger dans le code Arduino, la library CapSense (ou CapacitiveSensor). Cette dernière se charge de faire une boucle (while) de lecteur et test des pins.

A noter que l’on peut utiliser une seul pin Send avec plusieurs pin Receive, ce qui permet par exemple de n’utiliser que 4 pin pour faire 3 touches sensitives.

CapacitiveSensor mySensor(sendPin, reveicePin)
Crée l’objet CapacitiveSensor. En utilisant une paire spécifique de la broche. Vous devez créer un objet CapacitiveSensor distinct pour chaque capteur. Les capteurs peuvent partager le même sendPin, mais chaque besoin de ses propres reveicePin

mySensor.capacitiveSensor(numSamples)
Mesure le capteur. La mesure est répétée numSamples fois. Un grand nombre de mesures augmente la sensibilité, mais prend plus de temps de traitement.
Un temps écoulé, en unités arbitraires, est retourné. Un nombre négatif est retourné si une erreur survient.

La librairie contient aussi d’autres variables que je n’est pas encore exploré.

… »capacitiveSensor and capacitiveSensorRaw will return -2 if the methods timeout. This is caused by the count exceeding the value of CS_Timeout_Millis, which is set at a default value of 2000 milliseconds (2 seconds). This is most often caused by a missing resistor or the resistor in the wrong pin. It could also be caused by a sensor that is grounded or connected to +5 V…. …. »

La librairie va donc tester le nombre de fois ou la pin à détectée un doigt ou autre.
Au code alors de faire un test pour vérifier si la pin n’est pas activé par erreur (parasite, ondes…).
J’ai pas encore tout compris sur CS_Timeout_Millis mais il me semble que la boucle de test s’arrete au bout de 2 sec si il y a un problème de connectique ou branchement ???

Une broche étant considéré comme « émettrice » (send) et l’autre comme « réceptrice » (receive). La valeur de la résistance peut allez de 100 kΩ à 50 MΩ, selon le type de capteur (punaise, bout d’aluminium, fil…) et l’effet de proximité recherché :

  • Utilisez une résistance de 1 mégohm (ou moins peut-être) pour le toucher absolue pour l’activer.
  • Avec une résistance de 10 mégohm le capteur va commencer à répondre 4-6 centimètres.
  • Avec une résistance de 40 mégohm le capteur va commencer à répondre 12-24 centimètres (en fonction de la taille de la feuille).

Dans mon cas, j’ai utilisé des clous de tapissier en inox, reliés par un cable en nappe de 20cm et ça fonctionne bien.

Le code Arduino

En état, on peut afficher l’état on/off de la touche sensitive via le moniteur serie de de l’IDE Arduino (Ctrl+Maj+M) mais évidement la variable EtatBouton01 peut être utilisée pour déclencher des actions.

Avec 2 boutons

/*Testé sur Teensy 3.1*/

#include <CapacitiveSensor.h>

int TestBouton01;
int EtatBouton01;
int TestBouton02;
int EtatBouton02;
int TouchCommune = 14; // la pin "send"
int NBtestBoutons = 50; // nombres de test des boutons
int ValCapacitive = 2000; // valeur de l'entrée capacitive
CapacitiveSensor Bouton01 = CapacitiveSensor(TouchCommune,0); // une résistance de 1M entre les broches 14 et 1 = déclenchement en touchant du doigt la broche 0. 
CapacitiveSensor Bouton02 = CapacitiveSensor(TouchCommune,1); // une résistance de 1M entre les broches 14 et 2 = déclenchement en touchant du doigt la broche 1.

void setup() 
{
}

void loop() 
{
long TestBouton01 = Bouton01.capacitiveSensor(NBtestBoutons); // nombres de test du bouton
long TestBouton02 = Bouton02.capacitiveSensor(NBtestBoutons); // nombres de test du bouton
 if (TestBouton01 > ValCapacitive){ 
 EtatBouton01 = 1;
 Serial.print(" bouton 01 ");
 Serial.print("\n");
 delay(100);
 } 
 
 if (TestBouton02 > ValCapacitive){ 
 EtatBouton02 = 1;
 Serial.print(" bouton 02 "); // affiche 1e dans le moniteur serie
 Serial.print("\n");
 delay(100);
 } 
}

ValCapacitive est la valeur à partir de laquelle la touche est considéré comme déclenché.

NBtestBoutons est le nombre de fois ou la touche va être testé, grand = +précis mais +de ressource CPU utilisé.

Test

Pour définir la bonne valeur de déclenchement (ValCapacitive) au repos, il est souhaitable de faire un test qui affichera « ValCapacitive ». A noter, qu’au fil du temps, la valeur peut grossir. Donc, Si l’on voit qu’au bout 1/2 heure la valeur n’exede pas 1000 par exemple, on peut indiquer 1500 pour « ValCapacitive », histoire d’avoir un peux de marge.

Ce test permet aussi de tester l’isolation ou le blindage des fils reliant les boutons au Teensy, pour détecter d’éventuelle parasites.

Serial.print("BOUTON 01 : ");
Serial.print(TestBouton01);
Serial.print("\n");
Serial.print("BOUTON 02 : ");
Serial.print(TestBouton02);

Note

J’ai fait l’essais, en utilisant le même montage, de prendre une pin « Digital » et le résultat est le même ???.
Je n’ai pas plus creusé la question, 12 pin sensitive avec le Teensy 3.1 c’est déjà pas mal.

Améliorations

Un condensateur (100 pF – 0,01 uF) entre la masse et la pin du contact permet d’améliorer la stabilité du système.

Comme le système se sert de la terre pour fonctionner, un montage sur batterie (sans USB relié à un PC) aura peut être du mal. Dans ce cas, la solution être de placer près de la touche sensitive, une autre touche relié à la masse.

Il est conseillé aussi, pour l’utilisation de grande surface de touche, de placer sous les touches, une surface relié à la masse.

J’ai constaté aussi que le faite d’entourer les fils reliant les boutons avec un fil, ou un blindage, relié à la pin « receive » permet de faire baisser la valeur de « ValCapacitive »;

Anti-rebond

Dans beaucoup de système Arduino avec des boutons mécanique, on trouve des solutions pour éviter rebonds (debounce). Dans mes exmples, ça ne pose pas de soucis mais si vous voulez en rajouter une couche, vous pouvez allez voir ce tuto.

Sources

http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense

https://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html

A partir de la version 3

Avec la version 3 et 3.1, il n’est plus nécessaire d’inclure la librairy et de rajouter des résistances.

La lecture de la valeur (capacitive) de la pin se fait avec un simple : touchRead(numéro de pin);

Le principe reste le même que d’écris plus haut MAIS on peut supprimer une bonne partie du code.

Test de valeur capacitive moyenne au démarrage

Le système de touche capacitive dépendant de l’électricité ambiante, il peut être souhaitable de faire un test des touches AVANT de démarrer le programme.

J’ai rajouté aussi un système de tableau permettant de lire et d’attribuer, via une boucle for,  toutes les pins touchRead  du Teensy à autant de bouton (de 1 à 12).

/* Testé sur Tennsy 3.1 */
int calibrage = 4; // test X fois les boutons
int TestBouton[12];
int Bouton[12] = {1,2,3,4,5,6,7,8,9,10,11,12};
int PinBouton[12] = {0,1,15,16,17,18,19,22,23,25,32,33}; // PIN touchRead
int MaxTestBouton = TestBouton[0];
int SeuilBouton;

void setup()   {                
   Serial.begin(9600);
   pinMode(13, OUTPUT);
delay(1000);// si ça démarre au milieu d'un cycle   
//calibrage des pins boutons 
for (int i=1; i<=calibrage; i++)// lecture calibrage fois de chaque entrèes
{   
 for (int i=0; i<=11; i++)// lecture des 12 boutons  {      delay(100);// délai entre chaque test de bouton    TestBouton[i] = touchRead(PinBouton[i]);          Serial.print("Bouton ");         Serial.print(i+1);         Serial.print(" : ");         Serial.println(TestBouton[i]);          if (TestBouton[i] >MaxTestBouton)
{
  MaxTestBouton = TestBouton[i];
}
}
}           
SeuilBouton = MaxTestBouton+1000; // on ajoute une valeur significative
// au besoin, faire un test de valeur quand un bouton est touché
        Serial.println(" ");
        Serial.print("Valeur du bouton au repos : ");
        Serial.println(MaxTestBouton); 
        Serial.println(" ");
        Serial.print("Valeur de declenchement du bouton : ");
        Serial.println(SeuilBouton);
 
// a la fin du test, on fait clignoter la LED interne
digitalWrite(13, HIGH); 
delay(500);
digitalWrite(13, LOW);
}//setup

void loop(){ 
   
  for (int i=0; i<=11; i++)  {   Bouton[i] =  touchRead(PinBouton[i]);    }  if (Bouton[0] >= SeuilBouton)
{
  Serial.print("Bouton de la pin 0");
}
 
 }//loop

Test de valeur capacitive individuelle au démarrage

Si l’on a des boutons sensitives avec des valeurs au repos différentes (c’était mon cas même avec des boutons proches et sur un même support), un test qui renvoie une valeur de la plus élevé n’est pas bine conseillé.

J’ai fais un autre système permettant de tester (1 seul fois par contre) la valeur de tous les boutons et donc d’avoir une valeur de seuil (qui met sur ON) propre à chaque boutons.

int TestBouton[12]; // au démarrage
int Bouton[12] = {1,2,3,4,5,6,7,8,9,10,11,12};
int IntervalTestBouton = 200; // temps entre le test de chaques bouton
boolean EtatBouton[12]; // bouton touché ou au repos
int PinBouton[12] = {0,1,15,16,17,18,19,22,23,32,33,25}; // PIN touchRead
int ValeurSeuilBouton = 500; // ajout à la valeur testé au démarrage
int SeuilBouton[12]; // valeur ou les boutons sont considérés ON

void setup() {

//calibrage des pins boutons   
 for (int i=0; i<=11; i++)// lecture des 12 boutons
 {  
   delay(IntervalTestBouton);// délai entre chaque test de bouton
   TestBouton[i] = touchRead(PinBouton[i]); 
  SeuilBouton[i] = TestBouton[i]+ValeurSeuilBouton;
  
        Serial.println(" ");
        Serial.print("Valeur du bouton au repos : ");
        Serial.println(TestBouton[i]); 
        Serial.println(" ");
        Serial.print("Valeur de declenchement du bouton : ");
        Serial.println(SeuilBouton[i]);
}
}//setup

void loop() {
  
  /* BOUTONS SENSITIFS */  
  for (int i=0; i<=11; i++)
 {
  Bouton[i] =  touchRead(PinBouton[i]);

      if (touchRead(PinBouton[i]) > SeuilBouton[i])
      {
       EtatBouton[i] = true; 
       //Serial.println(EtatBouton[i]); 
      } 
      else
      {
        EtatBouton[i] = false;
       } 
  }

// on fait ce que'on veut
if (EtatBouton[0])
  {
// son code içi
  }



}//loop

Ajout d’un anti-rebond

Si l’on souhaites prémunir les touches des rebonds, ce qui peut être problématique si on envoie des données séries par exemple, j’ai rajouté un système qui détermine un temps minimum de déclenchement entre 2 touche du bouton.

A rajouter avant le setup

elapsedMillis  TempsBouton = 0;
int RebondBouton = 200; //  X milli-seconds minimum entres chaque touche de bouton

Et une petite modification du code de la loop

  /* BOUTONS SENSITIFS */
  for (int i=0; i<=11; i++)
 {
  Bouton[i] =  touchRead(PinBouton[i]);

      if (touchRead(PinBouton[i]) > SeuilBouton[i] && TempsBouton >= RebondBouton)
      {
TempsBouton = 0;
EtatBouton[i] = true; 
//Serial.println(EtatBouton[i]); 
      } 
      else
      {
        EtatBouton[i] = false;
      }        
  }

**

Infos

Créer un slider sensitif

Catégorie : Teensy/Arduino | Commenter