Nous allons voir dans ce tutoriel comment donner la parole à votre appareil Android avec une librairie Text to Speech (TTS). Que ce soit pour développer des applications pour malvoyant ou pour donner plus de vie à votre système Android, donner la parole à votre projet peut être une fonctionnalité intéressante. Pour cela nous allons intégrer la librairie react-native-tts dans un application Android développée avec React Native.
Matériel
Appareil Android
Ordinateur pour la programmation
Un câble USB pour connecter l’appareil Android au PC
Configuration du projet React Native
La librairie de conversion de texte en parole, react-native-tts permet d’utiliser les voix, ou modèles de synthèse vocale, disponibles sur votre appareil Android afin de lire du texte
npm install react-native-tts --save
Afin de pouvoir sélectionner la voix désirée, nous utilisons une liste déroulante
Tout d’abord, nous importons dans le code la librairie TextToSpeech ainsi que la liste déroulante
import Tts from 'react-native-tts'
import { SelectList } from 'react-native-dropdown-select-list'
Dans un composant fonctionnel, nous rajoutons les états qui nous intéresse:
voix sélectionnée
engin sélectionné
liste des voix
liste des engins
Il y a d’autres paramètres qui pourrait être intéressant à tester
defaultLanguage
defaultPitch défini la hauteur de la voix (aiguë ou grave)
defaultRate défini la vitesse de lecture de la voix
Dans un crochet useEffect, nous initialisons les listes de voix et des engins puis nous affectons la voix et l’engin sélectionné par défaut.
N.B.: Nous utilisons la promesse qui résulte de l’initialisation de l’engin TextToSpeech afin de nous assurer qu’il sera disponible à l’initialisation du composant (Tts.getInitStatus().then(() => {)
Une fois votre code compilé et installé sur votre appareil, vous pouvez sélectionner et tester les voix disponibles (les voix non-installées sont grisées). Entrez un texte et appuyer sur le bouton « Speak » pour faire parler votre application.
Une fois votre première application React Native créée et opérationnelle, vous voudrez peut-être réutiliser certains éléments comme composant fonctionnel. Ces composants peuvent alors être configurés pour d’autres applications et être partagés sous forme de librairie.
Description
Dans ce tutoriel, nous allons partir d’une application simple contenant quatre boutons. Nous allons créer un composant fonctionnel React Native configurable dans un fichier source que nous allons réutiliser dans le fichier principal l’application.
Nous allons voir comment:
passer des propriétés à un composant
récupérer les données d’un composant à partir d’évènement
utiliser un composant défini dans un fichier source dans le fichier principal
Application de base : 4 boutons
Dans ce code, nous allons avoir une vue principale (View) qui recouvre l’écran, le titre de l’application, et la vue qui va contenir les 4 boutons. Les fonctions exécutés lors des appuis et la définition des styles.
l’appui sur les boutons exécute bien les fonctions évènements
BUNDLE ./index.js
LOG Running "CustomApp" with {"rootTag":31}
LOG You clicked button Y
LOG You clicked button X
LOG You clicked button A
LOG You clicked button B
Appeler le composant à partir d’un fichier source
Nous allons placer ce code dans un fichier ./src/ACJoysticks.tsx et nous changeons le nom du composant en ButtonPad
Pour pouvoir l’utiliser, nous utilisons le mot-clé export pour définir la fonction
export const ButtonPad = () => {
...
}
Il est ensuite possible d’utiliser le composant en l’important
Pour rendre le composant configurable, nous définissons des paramètres dans le fichier principale qui seront passés dans les propriétés du composant. Les propriétés que nous souhaitons passer au composant sont:
le texte affiché sur les boutons
la couleur des boutons
la taille des boutons
la fonction onClick qui gère tous les boutons
Les paramètres du composant son placés dans un type ButtonPadProps
info Reloading app...
BUNDLE ./index.js
LOG Running "CustomApp" with {"rootTag":81}
LOG form ButtonPad: {"pressed": "╳", "states": [true, false, false, false]}
LOG form ButtonPad: {"pressed": "△", "states": [false, false, true, false]}
LOG form ButtonPad: {"pressed": "▢", "states": [false, false, false, true]}
LOG form ButtonPad: {"pressed": "◯", "states": [false, true, false, false]}
N.B.: pour faire les choses bien il faudrait créer les observateurs onPressIn et onPressOut pour repasser les états à zéro et modifier la logique pour écouter plusieurs bouton à la fois.
Nous allons voir dans ce tutoriel comment récupérer un flux vidéo Motion sur une application React Native.
Configuration du projet
Nous avons mis en place un stream vidéo avec Motion sur une machine Linux dont l’adresse est 192.168.1.92:8554 sur le réseau Wifi.
Le programme Motion sert les streams vidéo sous forme de page HTML avec le protocol HTTP. Pour récupérer cette page nous utilisons la librairie react-native-webview qui permet d’afficher des pages web complètes dans une application.
Pour installer la librairie, entrez la commande suivante
npm install --save react-native-webview
Utilisation de WebView
Pour utiliser le composant WebView, il nous suffit d’importer le composant
import {WebView} from 'react-native-webview'
et d’appeler le composant dans le rendu du composant fonctionnel App et de préciser la source de la vidéo
Pour aller plus loin, nous avons créé une encart textInput qui nous permet de mettre à jour l’url du stream (ou de la page web) avec les états ipAddress et ipServer. Vous pouvez retrouver les détails dans le code complet.
La vidéo s’affiche avec un délai inférieur à 3secondes et une qualité qui n’est pas très fluide.
Code complet de l’application React Native pour lire un flux vidéo Motion
Dans le code suivant nous définissons textInput qui va nous permettre de mettre à jour la valeur de ipAddress (valeur d’ip stockée) et lorsqu’on appuit sur le bouton, mettre à jour l’url lu par le composant WebView (ipServer)
Nous avons aussi rajouter l’affichage de la date et de l’heure (currentDate) en temps réel pour évaluer le délai de réception du flux vidéo. Nous avons commenté cette fonction car elle rafraichit l’application toute les secondes.
/**
* https://github.com/react-native-webview/react-native-webview
*/
import React, { useEffect, useState } from 'react'
import { Text, View, StyleSheet, TextInput, TouchableOpacity } from 'react-native'
import {WebView} from 'react-native-webview'
const App = () => {
const videoRef = React.createRef();
const [ipAddress, setIpAddress] = useState("http://192.168.1.92:8554/");
const [ipServer, setIpServer] = useState("http://192.168.1.92:8554/");
//const [currentDate, setCurrentDate] = useState('');
useEffect(() => {
/*setInterval(() => {
var date = new Date().getDate(); //Current Date
var month = new Date().getMonth() + 1; //Current Month
var year = new Date().getFullYear(); //Current Year
var hours = new Date().getHours(); //Current Hours
var min = new Date().getMinutes(); //Current Minutes
var sec = new Date().getSeconds(); //Current Seconds
setCurrentDate(
date + '/' + month + '/' + year + ' ' + hours + ':' + min + ':' + sec
);
}, 1000)*/
}, []);
console.log("rendering...");
return (
<View style={{ flexGrow: 1, flex: 1 }}>
<Text style={styles.mainTitle}>AC Video Player</Text>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={ipAddress}
onChangeText={(text) => setIpAddress(text)
}
/>
<TouchableOpacity
onPress={() => {
setIpServer(""); //force state change thus rendering
setIpServer(ipAddress);}
}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<View style={{flex: 1 }}>
<WebView
source={{uri: ipServer}}
style={styles.webVideo} />
</View>
{/*<Text style={{textAlign: 'right'}}>{currentDate}</Text>*/}
</View>
)
}
export default App;
let BACKGROUND_COLOR = "#161616"; //191A19
let BUTTON_COLOR = "#346751"; //1E5128
let ERROR_COLOR = "#C84B31"; //4E9F3D
let TEXT_COLOR = "#ECDBBA"; //D8E9A8
var styles = StyleSheet.create({
mainTitle:{
color: TEXT_COLOR,
fontSize: 30,
textAlign: 'center',
borderBottomWidth: 2,
borderBottomColor: ERROR_COLOR,
},
webVideo: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
buttonText: {
color: TEXT_COLOR,
fontWeight: 'bold',
fontSize: 12,
textAlign: 'center',
textAlignVertical: 'center',
},
sendButton: {
backgroundColor: BUTTON_COLOR,
padding: 15,
borderRadius: 15,
margin: 2,
paddingHorizontal: 20,
},
inputBar:{
flexDirection: 'row',
justifyContent: 'space-between',
margin: 5,
},
textInput:{
backgroundColor: '#888888',
margin: 2,
borderRadius: 15,
flex:3,
},
});
Nous allons voir dans ce tutoriel comment mettre en place un stream vidéo avec Motion à partir d’un Raspberry Pi. Ce tutoriel reste compatible avec tout système Linux.
Matériel
Raspberry Pi (ou autre machine linux)
Caméra USB ou Caméra CSI
Description de Motion
Le programme Motion a été développé comme système de surveillance. Il permet d’observer plusieurs caméras, détecter les mouvements sur chaque caméra et enregistrer des images ou des vidéos à ce moment là.
Cet outil permet donc
streamer les vidéos pour être affichées à distance
détecter des mouvements sur chacune des caméra
enregistrer des images ou des vidéos à partir des caméras
Installation de motion
Si ce n’est pas déjà le cas sur votre version d’OS, vous pouvez installer Motion à l’aide de la commande suivante.
sudo apt-get install motion
Vérification de l’installation
motion --version
Si une erreur apparait à propose de la permission d’accès au fichier /var/log/motion/motion.log
ou créer un autre fichier de log et ajouter son chemin d’accès dan le fichier motion.conf
sudo nano ~/.motion/motion.log
Configuration de motion
Toute la configuration de motion se fait dans le fichier /etc/motion/motion.conf. Vous pouvez directement modifier le fichier de configuration après avoir fait une copie en sauvegarde
Il existe un grand nombre de paramètre dans le fichier motion.conf qui vont vous permettre d’adapter l’acquisition d’image à votre besoin
Si plusieurs caméra sont utilisées, vous pouvez définir un jeu de paramètre pour chaque caméra (/etc/motion/camera1.conf)
Démarrer Motion depuis le terminal
sudo motion
sudo motion -c ~/.motion/motion.conf #to use another configuration file
sudo killall motion #to end the process
(utilise ~/.motion/motion.conf par défaut, s’il existe, sinon /etc/motion/motion.conf)
Démarrer Motion comme service
sudo service motion start
sudo service motion status
sudo service motion restart
sudo service motion stop
N.B.: Dans le fichier /etc/motion/motion.conf, laisser l’option daemon à OFF
Créer un stream vidéo avec Motion
Dans le fichier /etc/motion/motion.conf, modifier les paramètres par défaut
webcontrol_port
8080 # define http port for camera web control http://<ip_server>:<webcontrol_port>
webcontrol_localhost on # define if accessible only from the same machine
stream_port 8081 # define http port for camera display http://<ip_server>:<stream_port>
stream_localhost off
stream_auth_method
0
stream_authentication <username>:<password>
N.B.: si vous activer le webcontrol depuis l’extérieur de la machine, il est fortement conseillé d’activer l’authentification sur le stream
N’oubliez pas de redémarrer le service motion après toute modification du fichier motion.conf
sudo service motion restart
Si vous entrez l’adresse IP de votre machine Linux (ici, 192.168.1.92), suivie du numéro de port défini dans stream_port, vous pouvez observer le stream vidéo de motion.
Si vous n’utilisez pas motion en continu, il est possible d’enregistrer une vidéo sans attendre une détection de mouvement (emulate_motion on, event_gap -1)
Tips: vous pouvez définir une image de mauvaise qualité pour améliorer la bande passante du stream (stream_quality 45) mais conserver une image de bonne qualité pour l’enregistrement de la vidéo (video_quality 100).
Fichier motion.conf pour le streaming
/etc/motion/motion.conf (avec webcontrol local et ports 8553 et 8554)
# Rename this distribution example file to motion.conf
#
# This config file was generated by motion 4.3.2
# Documentation: /usr/share/doc/motion/motion_guide.html
#
# This file contains only the basic configuration options to get a
# system working. There are many more options available. Please
# consult the documentation for the complete list of all options.
#
############################################################
# System control configuration parameters
############################################################
# Start in daemon (background) mode and release terminal.
daemon off
# Start in Setup-Mode, daemon disabled.
setup_mode off
# File to store the process ID.
; pid_file value
# File to write logs messages into. If not defined stderr and syslog is used.
log_file /var/log/motion/motion.log
# Level of log messages [1..9] (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL).
log_level 6
# Target directory for pictures, snapshots and movies
target_dir /var/lib/motion
# Video device (e.g. /dev/video0) to be used for capturing.
videodevice /dev/video0
# Parameters to control video device. See motion_guide.html
; vid_control_params value
# The full URL of the network camera stream.
; netcam_url value
# Name of mmal camera (e.g. vc.ril.camera for pi camera).
; mmalcam_name value
# Camera control parameters (see raspivid/raspistill tool documentation)
; mmalcam_control_params value
############################################################
# Image Processing configuration parameters
############################################################
# Image width in pixels.
width 640
# Image height in pixels.
height 480
# Maximum number of frames to be captured per second.
framerate 10
# Text to be overlayed in the lower left corner of images
text_left CAMERA1
# Text to be overlayed in the lower right corner of images.
text_right %Y-%m-%d\n%T-%q - %{fps}
text_scale 3
############################################################
# Motion detection configuration parameters
############################################################
# Always save pictures and movies even if there was no motion.
emulate_motion off
# Threshold for number of changed pixels that triggers motion.
threshold 1500
# Noise threshold for the motion detection.
; noise_level 32
# Despeckle the image using (E/e)rode or (D/d)ilate or (l)abel.
despeckle_filter EedDl
# Number of images that must contain motion to trigger an event.
minimum_motion_frames 1
# Gap in seconds of no motion detected that triggers the end of an event.
event_gap 60
# The number of pre-captured (buffered) pictures from before motion.
pre_capture 3
# Number of frames to capture after motion is no longer detected.
post_capture 0
############################################################
# Script execution configuration parameters
############################################################
# Command to be executed when an event starts.
; on_event_start value
# Command to be executed when an event ends.
; on_event_end value
# Command to be executed when a movie file is closed.
; on_movie_end value
############################################################
# Picture output configuration parameters
############################################################
# Output pictures when motion is detected
picture_output off
# File name(without extension) for pictures relative to target directory
picture_filename %Y%m%d%H%M%S-%q
############################################################
# Movie output configuration parameters
############################################################
# Create movies of motion events.
movie_output on
# Maximum length of movie in seconds.
movie_max_time 60
# The encoding quality of the movie. (0=use bitrate. 1=worst quality, 100=best)
movie_quality 100
# Container/Codec to used for the movie. See motion_guide.html
movie_codec mkv
# File name(without extension) for movies relative to target directory
movie_filename %t-%v-%Y%m%d%H%M%S
############################################################
# Webcontrol configuration parameters
############################################################
# Port number used for the webcontrol.
webcontrol_port 8553
# Restrict webcontrol connections to the localhost.
webcontrol_localhost on
# Type of configuration options to allow via the webcontrol.
webcontrol_parms 0
############################################################
# Live stream configuration parameters
############################################################
# The port number for the live stream.
stream_port 8554
# Restrict stream connections to the localhost.
stream_localhost off
stream_quality 100
##############################################################
# Camera config files - One for each camera.
##############################################################
; camera /usr/etc/motion/camera1.conf
; camera /usr/etc/motion/camera2.conf
; camera /usr/etc/motion/camera3.conf
; camera /usr/etc/motion/camera4.conf
##############################################################
# Directory to read '.conf' files for cameras.
##############################################################
; camera_dir /usr/etc/motion/conf.d
Nous allons voir dans ce tutoriel comment streamer un flux vidéo à partir d’un Raspberry Pi avec Gstreamer. Un des outils de streaming les plus utilisé est FFMPEG. Nous testons ici, gstreamer car il y a moins de délai de transmission.
Une partie de Gstreamer est installée par défaut sous Raspbian. Nous allons simplement compléter l’installation avec quelques librairies supplémentaires.
# install a missing dependency
$ sudo apt-get install libx264-dev libjpeg-dev
# install the remaining plugins
$ sudo apt-get install libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgstreamer-plugins-bad1.0-dev \
gstreamer1.0-plugins-ugly \
gstreamer1.0-tools \
gstreamer1.0-gl \
gstreamer1.0-gtk3
# if you have Qt5 install this plugin
$ sudo apt-get install gstreamer1.0-qt5
# install if you want to work with audio
$ sudo apt-get install gstreamer1.0-pulseaudio
Pour tester l’installation, entrer la commande suivante
Pour recevoir le flux vidéo depuis le Raspberry Pi, nous utilisons un ordinateur Windows. Vous pouvez utiliser un autre appareil (RPi, Android, iOS, macOS).
La carte Rock Pi 4 de chez Radxa peut tourner avec un OS Debian, Ubuntu ou Android. Nous allons voir dans ce tutoriel comment configurer et utiliser votre micro-ordinateur avec Android.
Configurez ANDROID_HOME dans les variables d’environnement (C:\Users\ADMIN\AppData\Local\Android\Sdk)
Vérifier la version de Gradle (graddle-wrapper.properties) et du plugin Gradle (build.gradle)
Utilisation d’Android Debug Bridge
L’installation d’Android Studio vous donnera accès à Android Debug Bridge (ADB). ADB est un terminal de commande qui vous permet de communiquer avec un appareil Android depuis votre ordinateur.
Brancher le port USB 3 du Rock Pi, situé au-dessus, à l’ordinateur à l’aide du câble USB A vers USB A
Puis activer l’interrupteur, situé sous les ports USB (OTG switch), côté Rock Pi pour activer le mode Device. Une fois que l’appareil est connecté et reconnu par l’ordinateur, vous pouvez utiliser les commandes ADB depuis un terminal.
Pour vérifier que votre appareil est bien détecté
adb devices
Il est possible de transférer des fichiers depuis l’ordinateur au Rock pi à l’aide de la commande
adb push <local path> <remote path>
Pour transférer des fichiers depuis Rock Pi vers l’ordinateur
adb pull <remote path> <local path>
Accéder au fichier log Android
adb logcat
Pour vous connecter au Terminal de l’appareil
adb shell
or
adb -s <serial number> shell
N.B.: vous pouvez exécuter directement une commande sur l’appareil avec la commande adb shell <cmd>
Une fois dans le shell, vous pouvez naviguer dans le système de l’appareil. Voici quelques commandes utiles
getprop # display all properties
getprop ro.build.version.release # get android version
getprop ro.build.version.sdk # get API level
getprop vendor.serialno # get serial number
getprop ro.vendor.product.cpu.abilist # get CPU info
getprop ro.product.vendor.name #get device name
ifconfig #get network informations
Pour terminer la connexion du shell entrez la commande
exit
La plupart des accès aux fichiers système sont bloqués. Pour permettre l’accès aux dossiers, utiliser la commande su
su # enter super user mode
<enter command>
exit # exit super user mode
Pour éteindre l’appareil, vous pouvez utiliser la commande reboot
reboot -p
Télécharger un fichier APK
Il est possible de télécharger une application sur Google Play store ou sur internet directement.
Vous pouvez aussi récupérer un fichier APK que vous avez créé:
avec un clé USB
avec le drive ou la boite mail de Gmail
transférer le fichier avec SSH ou ADB
L’installation de l’apk peut se faire via l’interface graphique ou avec la ligne de commande
adb install -r <apk_file.apk>
Télécharger un terminal Linux sur votre RockPi
Pour pouvoir développer sous Android sur Rock Pi, il peut être intéressant d’utiliser un terminal. Voici deux applications que vous pouvez utiliser afin de naviguer sur votre appareil Android:
Pour éteindre l’appareil, au lieu de couper l’alimentation, vous pouvez activer le menu d’accessibilité dans Paramètres > Accessibilité > Menu d’accessibilité
Un bouton apparaitra en bas de l’écran et vous donnera accès à un menu d’icône contenant le bouton « Eteindre »
Nous allons voir dans ce tutoriel comment intégrer une vidéo dans une application React Native. Pour cela nous allons créer un stream vidéo à partir d’un ordinateur et récupérer le signal vidéo sur l’appareil Android.
Configuration du projet React Native
Pour intégrer une vidéo à l’application, nous utilisons la librairie react-native-video qui permet de lire des vidéo locales et distantes.
Pour ajouter la librairie à votre projet React Native, entrez la commande suivante
Pour tester notre application, nous utilisons l’outil ffmpeg pour créer un stream vidéo à partir d’un ordinateur connecté au même réseau wifi que l’appareil. L’ordinateur joue le role d’émetteur (le serveur) et l’application joue le rôle du récepteur (client).
Nous allons récupérer l’adresse IP du serveur (ipconfig ou ifconfig) ici 192.168.1.70 et nous allons émettre le fllux vidéo sur le port 8554
Nous allons voir dans ce tutoriel comment mettre en place un menu de navigation avec différents écrans dans React Native. Pour cela, nous allons utiliser la librairie React Navigation
N.B.: Une autre alternative react-native-navigation existe mais ne fonctionne pas avec mon environnement
package com.menuapp;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
import android.os.Bundle;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "MenuApp";
}
/**
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
* (aka React 18) with two boolean flags.
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
}
Code principal de l’application
Dans le code principal de l’application, index.js ou App.tsx, nous importons l’objet NavigationContainer. Pour l’utiliser, ils suffit d’entourer le code de rendu avec le tag correspondant. Dans cet exemple, nous définissons deux pages avec chacune un bouton permettant de se rendre à l’autre page.
N.B.: vous pouvez afficher ou non la barre de navigation avec l’option headerShown: false
Exemple: Création d’un menu
Dans cet exemple, nous allons créer une application simple pour afficher différents écrans. Ces écrans parte d’une même composant qui est adapté en fonction des informations contenus dans une liste.
Tout d’abord nous créons un array contenant toutes les informations dont nous avons besoin
Nous créons ensuite l’écran principal qui contient les boutons permettant de naviguer vers les autres écrans
Sur cet écran, nous ajoutons un bouton pour chaque écran avec la fonction buttonListArr que nous personnalisons avec les données contenu dans screensArr.
Il est possible d’ajouter ou de remplacer le texte par une icône.
npm install react-native-vector-icons --save
Pour cela vous devez importer chaque banque d’icone. Trouver les icônes que vous souhaitez ajouter et dans quelle banque
import Icon from 'react-native-vector-icons/FontAwesome6';
import IonIcon from 'react-native-vector-icons/Ionicons'
import MaterialIcon from 'react-native-vector-icons/MaterialIcons'
Vous pouvez ensuite placer l’objet Icon correspondant à la banque contenant l’icone
Dans ce tutoriel, nous allons mettre en place une communication avec le protocole UDP sur une application React Native. L’application React Native pourra se comporter comme Serveur ou comme Client UDP. Nous utilisons un ordinateur avec un script Python comme partenaire de communication.
Pour utiliser les librairies, nous importons tout d’abord leur code.
import dgram from 'react-native-udp'
import UdpSocket from 'react-native-udp/lib/types/UdpSocket.js';
import { NetworkInfo } from 'react-native-network-info'
Composant principal
Puis nous créons le composant fonctionnel qui nous permettra de gérer la communication Serveur/Client UDP.
N.B.: le style de l’interface est défini dans le fichier /src/styles/styles.jsx
React-Native UDP Client – Python UDP Server
Dans cet exemple, nous configurons l’application comme client et l’ordinateur comme serveur. Nous allons envoyer un message au serveur, depuis l’application, qui renverra une réponse au client.
Python UDP Server Code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
localIP = "0.0.0.0" #"127.0.0.1"
localPort = 8888
bufferSize = 1024
msgFromServer = "Hello UDP Client"
bytesToSend = str.encode(msgFromServer)
# Create a datagram socket
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# Bind to address and ip
UDPServerSocket.bind((localIP, localPort))
print("UDP server up and listening on port {}".format(localPort))
# Listen for incoming datagrams
while(True):
data,addr = UDPServerSocket.recvfrom(bufferSize)
print("{} > {}".format(addr,data))
# Sending a reply to client
UDPServerSocket.sendto(bytesToSend, addr)
N.B.: Pour écouter sur toutes les adresses locales nous utilisons 0.0.0.0. Si vous souhaitez tester la communication entre client et serveur sur le même ordinateur vous pouvez utiliser l’adresse 127.0.0.1
Sur l’application, dans l’encart ServerIp, entrez l’adresse IP de l’ordinateur (ici: 192.168.1.70). Modifiez ensuite le message à envoyer puis appuyer sur le bouton « SEND ».
Python terminal
UDP server up and listening on port 8888
('192.168.1.5', 8887) > b'Hello server'
('192.168.1.5', 8887) > b'Hello server'
Sur le terminal Python, nous recevons le message « Hello server » envoyé depuis l’application. Le serveur UDP renvoie « Hello UDP Client »
React-Native UDP Server – Python UDP Client
Ici, nous configurons l’application comme serveur et l’ordinateur comme client. Dans le code Python, nous entrons l’adresse IP du serveur.
Python UDP Client
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import time
HOST = "192.168.1.5" #Server IP #"127.0.0.1" local address
PORT = 8888
bufferSize = 1024
counter=0
while True:
# Create a UDP socket at client side
with socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) as client:
# Send to server using created UDP socket
client.sendto(str.encode("client counter : "+str(counter)), (HOST,PORT))
data,addr= client.recvfrom(bufferSize)
msg = "{} > {}".format(addr,data)
print(msg)
counter+=1
time.sleep(1)
Nous allons voir comment créer une application React Native pour Adnroid permettant la communication BLE (Bluetooth Low Energy) avec un ESP32. Nous utilisons React Native pour développer un terminal BLE sur Android permettant la communication avec un NodeMCU ESP32 ou tout autres appareils compatibles.
Matériel
Un ordinateur avec installation de React Native et Node.js
Un appareil Android avec BLE
Un câble USB pour relier l’ordinateur à l’appareil
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp
Ported to Arduino ESP32 by Evandro Copercini
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic *pCharacteristic = NULL;
std::string msg;
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
}
}
};
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("Client connected");
}
void onDisconnect(BLEServer* pServer) {
Serial.println("Client disconnected");
BLEDevice::startAdvertising(); // needed for reconnection
}
};
void setup() {
Serial.begin(115200);
Serial.println("1- Download and install an BLE Terminal Free");
Serial.println("2- Scan for BLE devices in the app");
Serial.println("3- Connect to ESP32BLE");
Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");
BLEDevice::init("ESP32BLE");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->setValue("Hello World");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
pAdvertising->start();
Serial.print("Server address:");
Serial.println(BLEDevice::getAddress().toString().c_str());
}
void loop() {
readSerialPort();
//Send data to slave
if(msg!=""){
pCharacteristic->setValue(msg);
msg="";
}
delay(2000);
}
void readSerialPort(){
while (Serial.available()) {
delay(10);
if (Serial.available() >0) {
char c = Serial.read(); //gets one byte from serial buffer
msg += c; //add to String
}
}
Serial.flush(); //clean buffer
}
Nous rajoutons la fonction BLEServerCallbacks à la gestion du Serveur BLE pour détecter la déconnexion et démarrer l’advertising pour pouvoir reconnecter l’ESP32
pServer->setCallbacks(new MyServerCallbacks());
Application React Native pour la gestion du BLE
Pour gérer la communciation BLE (Bluetooth Low Energy) sur l’appareil Android, nous utilisons la librairie react-native-ble-manager
npm install react-native-ble-manager --save
Pour mettre en place le projet de l’application, suivez le tutoriel précédent.
Dans le fichier App.tsx, pour utiliser la bibliothèque nous l’importons à l’aide de la commande
import BleManager from 'react-native-ble-manager';
Nous créons un composant fonctionnel qui contiendra les éléments nous permettant de gérer la communication BLE
Comme l’appairage n’est pas gérer par l’application, il faut appairer l’ESP32 avant l’utilisation de l’application. Une fois le code chargé sur l’ESP32, vous pouvez lancer l’application sur le téléphone à l’aide de la commande