Bonsoir à tous,
Après les connexions en utilisant les Datagrams UDP voici la version des sockets TCP.
Utilisation de Lua
ou des commandes AT coté esp8266 et Python sur Raspberry coté serveur.
La gestion en Sockets TCP permet d’avoir :
Plusieurs clients en simultanés
Dialogue bidirectionnel par exemple pour: Acquitter les messages, ou demande de reboot des clients (A développer).
Une gestion automatique des reconnexions suite à : Une relance du serveur, Un reboot d’un client.
(Non testé sur commandes AT).
Trace coté client de l’esp8266 N°5 d’adresse IP 192.168.1.255
Le serveur renvoie au client son propre message.
Code : Tout sélectionner
NodeMcu 0.9.5 build 20150105 powered by Lua 5.1.4
192.168.1.155
en cours
CreatConnexion ok statuts =
Connexion
Reçu ->Connexion Ok avec le serveur
Envoi ->capteur5=240
Reçu ->Thread-1> statut=C Capteur5=240
Envoi ->capteur5=71
Reçu ->Thread-1> statut=C Capteur5=71
Trace coté serveur avec deux clients connectés N°5 et N°7.
Arrêt des messages du serveur par CTRL+Z
Code : Tout sélectionner
pi@raspberrypi:~/esp8266/tcp$ python serveur_tcp.py
Serveur en attente de connexions
Connexion client Thread-1 d'adresse IP 192.168.1.155, port 4098.
Thread-1> statut=C Capteur5=240
Thread-1> statut=C Capteur5=71
Connexion client Thread-2 d'adresse IP 192.168.1.157, port 34387.
Thread-1> statut=C Capteur5=100
Thread-2> statut=C Capteur7=9
Thread-1> statut=C Capteur5=93
Thread-2> statut=C Capteur7=11
^Z
[1]+ Stop python serveur_tcp.py
Liste des connexions TCP coté serveur.
On peut lister avec la commande netstat les connexions TCP sur le port 5005 (en utilisant un grep)
On retrouve bien les deux adresse ip des deux esp8266
Code : Tout sélectionner
pi@raspberrypi:~$ netstat |grep 5005
tcp 0 0 pc33.home:5005 192.168.1.155:22629 ESTABLISHED
tcp 0 0 pc33.home:5005 192.168.1.157:23541 ESTABLISHED
pi@raspberrypi:~$
Pour tuer définitivement le serveur, il faut faire un kill -9 du process
Code : Tout sélectionner
En premier on liste par la commande ps les process utilisant Python et ensuite on arrête le serveur serveur_tcp.py
pi@raspberrypi:~/esp8266/tcp$ ps -edf |grep python
pi 3606 3587 0 18:38 pts/0 00:00:00 python serveur_tcp.py
pi 3615 3587 0 18:45 pts/0 00:00:00 grep python
pi@raspberrypi:~/esp8266/tcp$ kill -9 3606
[1]+ Processus python serveur_tcp.py
Essais avec les commandes AT à la place de Lua.
Le serveur DHCP du routeur a affecté l’adresse 192.168.1.20 à l’esp8266
Essai d’envoi de 5 caractères 12345
Code : Tout sélectionner
AT+CWMODE=3
OK
AT+CWJAP="SSID","mot de passe"
OK
AT+CIPMUX=1
OK
AT+CIPSTART=0,"TCP","192.168.1.22",5005
0,CONNECT
OK
+IPD,0,28:Connexion Ok avec le serveur
OK
AT+CIPSEND=0,5
> 12345busy s...
SEND OK
+IPD,0,17:->Thread-1> 12345
OK
Avec les commandes AT la connexion est bidirectionnelle (le serveur peut répondre au client)
Les messages reçus du serveur sont post fixés par "+IPD,0,17" (canal, longueur).
A la connexion le serveur envoi le message "Connexion Ok avec le serveur" à l'esp8266
L’esp8266 en commandes AT récupère bien le message "->Thread-1> 12345" renvoyé par le serveur.
Trace coté serveur
Code : Tout sélectionner
pi@raspberrypi:~/esp8266/tcp$ python serveur_tcp.py
Serveur en attente de connexions
Connexion client Thread-1 d'adresse IP 192.168.1.20, port 29675.
Thread-1> 12345
Et pour finir les sources.
Côté Lua.
Code : Tout sélectionner
tmr.delay(2000000) -- pour prise de main si PB
IP_routeur="192.168.1.1"
IP_serveur="192.168.1.22"
IP_client="192.168.1.157"
CAPTEUR="7"
statut=""
wifi.setmode(wifi.STATION) -- Wifi en mode station
cfg = { ip=IP_client, netmask="255.255.255.0", gatway=IP_routeur}
wifi.sta.setip(cfg) -- on force l'adresse IP
wifi.sta.config("SSID","mot de passe")
print(wifi.sta.getip()) -- vérification adresse IP
function connected()
if (statut =="D") then conn=net.createConnection(net.TCP, 0) statut="x" end
if (conn ~= nil) then print ("CreatConnexion ok statuts = " .. statut ) end
if (statut ~="C") then conn:connect(5005,IP_serveur) end
end
conn=net.createConnection(net.TCP, 0)
tmr.alarm(0,2000, 1, function() if statut ~= "C" then connected() end end )
conn:on("receive", function(conn, payload) print("Reçu ->" .. payload) end)
conn:on("sent",function(conn) print("Envoi ->capteur"..CAPTEUR.."=" ..capteur) end)
conn:on("disconnection", function(conn) print("Deconnexion") statut="D" conn:close() end)
conn:on("connection", function(conn) print("Connexion") statut="C" end)
conn:on("reconnection", function(conn) print("Reconnexion") statut="C" end)
tmr.alarm(1,2000, 1, function() capteur=adc.read(0)
if (statut=="C") then conn:send("statut=" .. statut .. " Capteur" ..CAPTEUR .."=" .. capteur ) end end) -- lecture capteur
print("en cours")
Et coté serveur en python
Récupéré sur Wikibooks avec ajout de quelques modifications et commentaires.
http://fr.wikibooks.org/wiki/Apprendre_ ... %C3%A9seau
Code : Tout sélectionner
#
# -*- coding: utf8 -*-
# Serveur TCP en attentes messages des ESP8266
# Utilise les threads pour traiter les connexions clientes
HOST = '192.168.1.22' # Adresse du serveur
PORT = 5005 # Port d'ecoute
NBCLIENTS=6 # nbclients
import socket, sys, threading
class ThreadClient(threading.Thread):
'''Gestion des treads '''
def __init__(self, conn):
threading.Thread.__init__(self)
self.connexion = conn
def run(self):
# Dialogue avec le client :
nom = self.getName() # Chaque thread dispose d'un nom
while 1:
msgClient = self.connexion.recv(1024)
if msgClient.upper() == "FIN" or msgClient =="":
break
message = "%s> %s" % (nom, msgClient)
print message
# acquitement
for cle in conn_client:
if cle == nom: # Acquitement
conn_client[cle].send("->" + message)
# Fermeture de la connexion :
self.connexion.close() # couper la connexion au serveur
del conn_client[nom] # supprimer nom dans le dictionnaire
print "Arret Client %s " % nom
# Le thread se termine ici
# Initialisation du serveur - Mise en place du socket :
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
mySocket.bind((HOST, PORT))
except socket.error:
print "Erreur de liaison du socket d'adresse choisie"
sys.exit()
print "Serveur en attente de connexions"
mySocket.listen(NBCLIENTS)
# Attente et prise en charge des connexions des clients :
conn_client = {} # dictionnaire des connexions clients
while 1:
connexion, adresse = mySocket.accept()
# Nouveau thread pour la connexion d'un client :
th = ThreadClient(connexion)
th.start()
# MAJ connexion dans le dictionnaire :
it = th.getName() # identifiant du thread
conn_client[it] = connexion
print "Connexion client %s d'adresse IP %s, port %s." %\
(it, adresse[0], adresse[1])
# Dialogue avec le client :
connexion.send("Connexion Ok avec le serveur")
Jean-Marie, tu peux utiliser seulement le programme python sur un Raspberry pour tester des clients.
C'est tout pour aujourd'hui.
Michel.