Salve ragazzi, ho realizzato una caldaia a pompa di calore ad inverter con elettronica gestita da Arduino e funziona alla grande già da qualche anno ormai con 500W mi scalda tutta la casa e mi fa pure l'acqua calda per la doccia.
Dialoga con un altra scheda Arduino via TCP ethernet W5100 per prendersi le temperature delle stanze ed accendere la pompa di mandata.
Tra loro sono buone amiche e si capiscono bene.
Ora però sto cercando di presentargli un nuovo amico.
In sostanza con una R4 WI FI sto cercando di prendermi i dati da entrambe le schede e mandarli su cloud per accenderla e spegnerla da app ed inoltre inviare attraverso la R4 i valori che prima si scambiavano tra loro.
Io pensavo ad un architettura singolo client e multi server.
Ci sono quasi riuscito ho solo il problema che i dati alla R4 mi arrivano mischiati.
Qualcuno ha già fatto una connessione di questo tipo?
Grazie.
Che intendi con "mischiati"?
I dati non sono strutturati in qualche modo?
In pratica la R4 esegue un interrogazione alla prima scheda server e riceve dei valori di temperatura.
questi valori li stampa su seriale (per ora). Fatto questo, resetta il millis e interroga la seconda scheda, riceve i relativi valori e li stampa su seriale. così dovrebbe fare per adesso.
I realtà mi trovo dei valori della prima scheda stampati in seriale al posto dei valori della seconda.
Tipo: Temperatura camera 18 ( dalla prima scheda ), Temperatura mandata impianto 45 ( dalla seconda scheda ). Ciclicamente mi trovo Temperatura camera 45 e temperatura mandata impianto 18.
I dati sono mandati attraverso String ,separati tramite indexof e convertiti in interi.
Per la prima scheda uso lettere "A" "B" "C" "D" per la seconda visto che i valori sono 2 uso " ," e "\n". Quindi non dovrebbe fare "confusione"
vedere il sorgente
[quote="doctormosfet, post:3, topic:1204696"]
I dati sono mandati attraverso String
classico inizio di un disastro...
Lo so ragazzi String non è il massimo, però vi confesso che uso questo scambio dati da qualche anno e non mi è mai andato in crash.
La pompa di calore va h24 da tre anni.
E comunque io ho anche cercato una valida alternativa ma non è che se ci siano molti esempi in giro.
Comunque questo è il codice ( spero di mandarlo nella forma corretta)
#include "WiFiS3.h"
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int Temperatura1;
int Temperatura2;
int Temperatura3;
int Pompa;
String line1;
int TemperaturaRiscaldamento;
int TemperaturaSanitario;
String line2;
int status = WL_IDLE_STATUS;
// Initialize the WiFi client library
WiFiClient client;
IPAddress server1(192,168,1,6);
IPAddress server2(192,168,1,4);
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
const unsigned long postingInterval1 = 9000; // delay between updates, in milliseconds
const unsigned long postingInterval2 = 9000; // delay between updates, in milliseconds
/* -------------------------------------------------------------------------- */
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
}
}
void loop() {
while (client.available()) {
String line1 = client.readString();
int a1 = 0;
int b1 = line1.indexOf("A");
String token1 = line1.substring (b1, a1); // Temperatura1
int c1 = (b1 + 1);
int d1 = line1.indexOf("B");
String token2 = line1.substring (d1, c1); // Temperatura2
int e1 = (d1 + 1);
int f1 = line1.indexOf("C");
String token3 = line1.substring (f1, e1); // Temperatura3
int g1 = (f1 + 1);
int h1 = line1.indexOf("D");
String token4 = line1.substring (h1, g1); //Temperatura4
Temperatura1 = token1.toInt();
Temperatura2 = token2.toInt();
Temperatura3 = token3.toInt();
Pompa = token4.toInt();
}
if (millis() - lastConnectionTime > postingInterval1) {
client.stop();
if (client.connect(server2, 80)) {
Serial.println("Connessione caldaia");
client.println(2000);
client.println();
// note the time that the connection was made:
lastConnectionTime = millis(); //resetto il timer per la 1°connessione
Serial.println(" TEMPERATURA MANDATA RISCALDAMENTO");
Serial.println(TemperaturaRiscaldamento);
Serial.println(" TEMPERATURA MANDATA SANITARIO");
Serial.println(TemperaturaSanitario);
} else {
// if you couldn't make a connection:
Serial.println("connection failed");
}
}
while (client.available()) {
String line2 = client.readString();
int a1 = 0;
int b1 = line2.indexOf(",");
String token1 = line2.substring (b1, a1); // Temperatura impianto riscaldamento
int c1 = (b1 + 1);
int d1 = line2.indexOf("/n");
String token2 = line2.substring (d1, c1); // Temperatura acqua sanitaria
TemperaturaRiscaldamento = token1.toInt();
TemperaturaSanitario = token2.toInt();
}
if (millis() - lastConnectionTime > postingInterval2) {
client.stop();
if (client.connect(server1, 80)) {
Serial.println("Connessione centralina riscaldamento");
client.println(2);
client.println();
// note the time that the connection was made:
lastConnectionTime = millis();
Serial.println(" TEMPERATURE ZONA GIORNO");
Serial.println(Temperatura1);
Serial.println(Temperatura2);
Serial.println(Temperatura3);
Serial.println("COMANDO POMPA");
Serial.println(Pompa);
} else {
// if you couldn't make a connection:
Serial.println("connection failed");
}
}
}
perdona, ma per quello che ho capito io i due trasmettitori trasmettono di continuo (o comunque per loro iniziativa e senza un sincronismo) e tu nella loop stai in attesa prima di uno e poi dell'altro con un readstring() prima di uno e poi dell'altro sperando di prenderli nell'ordine e nei tempi giusti? senza tentar di capire quale delle trasmissioni hai appena ricevuto?
Auguri
come minimo dovresti stampare per debug quello che ricevi, per capire almeno se i dati arrivano tra di loro separati e/o ben distanziati
In teoria no.
I server lavorano sulla chiamata del client " client.println (2000); client.println (); " per il primo server e " client.println (2); client.println (); " per il secondo.
In realtà a fine progetto le schede dovrebbero essere 5 quindi se non do un sincronismo finisco al neuro.
Scusate ma non posso mandarvi il codice completo perchè è sull'altro computer quindi vi mando la parte di trasmissione.
Server 1 con questo codice
` String Dati_verso_head = String(Temperatura1,DEC)+"A"+String (Temperatura2,DEC)+"B"+ String (Temperatura3,DEC)+"C"+ String (Temperatura4,DEC)+"D";
EthernetClient client = server.available()
if (client) {
client.flush()
Serial.println (" NUOVO CLIENT");
client.println (Dati_verso_head);
client.println();
}
if (client.available>0){
String line = client.readString();
Serial.println (line);
} `
Per il server 2 è circa lo stesso codice.
Uso lo String perchè per ora dal client invio solo un valore ma poi ne invierò 4 o 5 usando lo stesso metodo
complicato ma non sembra fallato, il tx
ma io non ho mica capito dove fai le print verso i due client
non riseco a capire:
stampi i valori prima di cercarli nella stringa in ricezione?
certo che trovi valori vecchi
devo staccare
a domani
In realtà i valori li stampavo subito dopo la conversione " token . toInt ()"
Li ho spostati per vedere se cambiava qualcosa ma peggiora solamente.
Secondo me il tuo problema è duplice:
- nel tuo messaggio manca una chiave che identifica in modo univoco il server che sta inviando i dati
- non gestisci la concorrenzialità dei dati che ti possono arrivare dai server (che infatti interroghi più o meno nello stesso momento)
Invece che perdere tempo con un algoritmo che è evidentemente debole come quello che hai implementato fino ad ora, io rivedrei tutto l'approccio:
Distribuisci meglio le richieste che fai ai server: ad esempio dopo aver processato la prima, potresti inserire un breve delay di 100/200ms cosi sei ragionevolmente sicuro di non ricevere le due risposte contemporaneamente ( ci sono modi migliori del delay ovviamente, ma in quest'applicazione non crea troppi problemi)
I dati che ti arrivano via WiFi vanno letti tutti nello stesso momento e salvati in un buffer (che può essere anche una variabile String
, io non ci vedo alcun problema in merito. Specie se usata in modo locale). Deciderai in un secondo momento chi è stato ad inviarli in base al contenuto.
Una volta che hai letto TUTTI i dati, li passi al "parser" che potrebbe essere una bella funzioncina distinta in modo da non creare confusione nel loop()
.
Ad esempio qualcosa del genere (ho usato la seriale al posto del WiFi, ma trattandosi comunque di uno stream di dati, il risultato non cambia)
Inserire i delay era una cosa che avevo già provato.
La cosa strana è questa:
Quando mando la richiesta al primo server lui mi risponde correttamente e nella seriale mi stampa lo String corretto e idem quando mando la richiesta al secondo server.
Quindi nella seriale mi trovo:
"connessione centralina riscaldamento"
21A22B23C2D
"connessione caldaia"
34,45
E questo avviene sempre quindi vuol dire che le stringhe arrivano giuste.
Se invece inserisco i valori dei parse tutto cambia e nella seriale mi trovo questo:
" connessione centralina riscaldamento"
21A22B23C2D
Temperatura mandata impianto ( che è nell'altra chiamata)
34
21
"connessione caldaia"
34,45
Temperature zona giorno
45
45
45
"comando pompa"
34
Sembra che la seriale non segua il ciclo while e se ne vada per i fatti suoi
Ora provo a mettere tutto insieme e vediamo che succede.
L'esempio che mi hai mandato potrebbe andare, usi un if per connetterti al primo ed un else per il secondo.
Nel wifi della R4 non credo funzioni perchè ha bisogno di 9 secondi per connettersi (postInterval1 e 2)
altrimenti va i connection failed e sotto a 9000 non si riesce a scendere.
E poi io devo gestire 5 schede e comandarle con la head.
Il valore "client.println (2000 ); è un int perchè viene da una terza scheda che lo manda alla head e la head lo "gira" al sever2 che lo usa per comandare l'inverter del compressore della pompa di calore.
L'errore che si fa di solito con gli stream è pensare che il flusso dei dati debba necessariamente arrivare tutto nello stesso momento senza soluzione di continuità.
Nel mondo reale questo non accade ed i dati arrivano sempre spezzettati e un po' per volta.
Questo vale sia per la Seriale che per il client WiFi.
Se sviluppi il tuo algoritmo secondo questo principio, avrai sempre problemi che "sembrano" inspiegabili perché ti aspetti un comportamento che poi non esiste.
Si in effetti mi ero fatto questa idea.
La stranezza è che "temperatura zona giorno" non è un dato è una scritta che metto nel Serial.println all'interno di un ciclo while e che la scheda dovrebbe stamparmi quando il millis comanda quel ciclo while. io invece me lo trovo delle volte su uno e altre volte sull'altro while.
Questa è la cosa strana, come se la seriale se ne fregasse del millis.
Comunque provo a metter insieme un codice usando un parse unico e vediamo cosa succede.
Io questi li chiamo "MIR" ( misteri informatici rompiballe )
concordo in pieno
anche qui
io li parserizzerei mano a mano
ci sono molti esempi qui sul forum
e ci aggiungerei che comincierei a scrivere le lettere A B C "prima" della prima variabile, così so quando è cominciata una trasmissione
e per la seconda trasmissione non userei le virgole, ma un differente insieme di lettere: G H I per esempio
e alla fine della trasmissione non uso una lettera, ma un carattere dedicato, per esempio un dollaro (grazie, lo prendo volentieri)
e si' ovvio
la serial readstring per sua natura è asincorna
invece quella scrittura tu la hai resa sincrona, o meglio a tempi predefiniti
ovvio che vanno per due strade differenti
se ci aggiungi che non sai se la prima variabile che sstai leggendo è realmente la prima perchè magari c'era ancora roba nel buffer di seriale, che non svuoti mai
e comunque sai che è la prima, ma per come hai scritto non sai se è la prima del server uno e del server due, che non hanno un identificatore univoco
insomma butta via TUTTO
e riparti da capo dopo aver ben pensato a quello che stai facendo
ricorda che arduino è velocissimo, la rete no (non con gli shield di arduino)
la seriale anche peggio
se non controlli TU i tempi ti trovi in CIAO: Casini Informatici AutoindOtti
PS
elimina gli ogggetti Stringa, subito, adesso
essi non ti aiutano a pensare in termini di array di caratteri e singoli caratteri che arrivano "singolarmente" dalla comunicazione
e tu così devi pensare
Scusa C1 ma non capisco cosa vuoi dire:
Io della seriale non me ne faccio niente la uso solo per vedere se le variabili sono assegnate correttamente poi va tutto su cloud.
Le stringhe arrivano corrette e distinte tra le due schede ( line1 e line2 ) il parse dei valori viene fatto con le lettere ( ho cambiato "," e "\n" con "E" ed "F " non è cambiato niente ) e pertanto dove sia la posizione sul buffer cambia poco visto che sono le lettere che identificano il dato.
Svuotare il buffer della seriale ci ho provato tante volte senza mai riuscirci e francamente penso che il serial.flush non funzioni, almeno su arduino e comunque la seriale poi sparisce.
La "serial read string"non la uso perche è un wi fi, parserizzare mano a mano lo sto già facendo
Francamente non capisco cosa stai cercando di dirmi
Ok butto via tutto e lo sostituisco con cosa?