-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cpp
executable file
·446 lines (388 loc) · 13 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <fstream>
#include <cmath>
#include <wiringPi.h>
#include <curl/curl.h>
#include "server_socket.h"
#include "client_socket.h"
#include "sql.h"
using namespace std;
using namespace rapidjson;
ostringstream url;
const char* cc;
Document d;
Document d2;
string s;
extern boost::mutex a;
boost::mutex a;
double arrosage;
int i = 0;
int nbEv = 0;
int ev1 = 1;
int ev2 = 1;
int ev3 = 1;
int ev4 = 0;
int heure = 0;
int surface1 = 0;
int surface2 = 0;
int surface3 = 0;
int surface4 = 0;
int e = 0;
int bz = 0;
int bq = 0;
bool m_pause; // a initialiser à "false" dans le constructeur si dans une classe ou dans le main
boost::mutex m_pause_mutex; // variable for the mutex
boost::condition_variable m_pause_changed; // condition variable, utile
string jDate, jEvp, jPrecipitation;
CURL *curl;
CURLcode res;
std::string readBuffer;
aquasql connectBdd("localhost","root","enzolepd","aquatech");
void block_while_paused() // permet de bloquer le programme pendant que m_pause est vrai
{
boost::unique_lock<boost::mutex> lock(m_pause_mutex); // initialise une variable lick en tant que mutex
while(m_pause) // si m_pause est vrai
{
m_pause_changed.wait(lock); // permert de lock le mutex
}
}
void set_paused(bool new_value) // change la valeur de la variable pause, permet de 'pauser' le thread
{
{
boost::unique_lock<boost::mutex> lock(m_pause_mutex); // reinitialise la variable lock qui est la même que au dessus
m_pause = new_value; // change la valeur de m_pause en fonction de la valeur donnée à la variable
}
m_pause_changed.notify_all();
if(new_value == true) // simple retour visuel
{
std::cout << "thread en pause dejeuner ! " << std::endl;
}
else if(new_value == false)
{
std::cout << "thread recommence a travailler !" << std::endl;
}
}
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size *nmemb);
return size *nmemb;
}
double calculArrosage(const int surface)
{
double whole, fractional;
//lock le mutex le temps de la manipulation de variables afin de ne pas avoir de surprises
a.lock();
//calcul d'arrosage
arrosage = (((atof(jEvp.c_str()) - atof(jPrecipitation.c_str())) / 1000 ) * surface) * 1000;
//arrosage = 3;
//petit algorithme matematique qui, comme l'on ne peut pas arosser de fraction de litre, s'occupe d'arrondir le nombre a l'unite inferieur ou superieur selon la valeur decimale
fractional = modf(arrosage, &whole);
if(fractional <= 0.5)
arrosage = whole;
else if(fractional > 0.5)
arrosage = whole + 1;
//tout est fini, debloque le mutex
a.unlock();
//retourne le nombre de litres
return(arrosage);
}
void getData()
{
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "127.0.0.1/settings.json");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
//cout << readBuffer << endl;
d.Parse(readBuffer.c_str());
nbEv = atoi(d["electrovannes"].GetString());
switch(nbEv)
{
case 0 :
{
ev1 = 0;
ev2 = 0;
ev3 = 0;
ev4 = 0;
surface1 = 0;
surface2 = 0;
surface3 = 0;
surface4 = 0;
}break;
case 1 :
{
ev1 = 1;
ev2 = 0;
ev3 = 0;
ev4 = 0;
surface1 = atoi(d["surface1"].GetString());
surface2 = 0;
surface3 = 0;
surface4 = 0;
}break;
case 2 :
{
ev1 = 1;
ev2 = 1;
ev3 = 0;
ev4 = 0;
surface1 = atoi(d["surface1"].GetString());
surface2 = atoi(d["surface2"].GetString());
surface3 = 0;
surface4 = 0;
}break;
case 3 :
{
ev1 = 1;
ev2 = 1;
ev3 = 1;
ev4 = 0;
surface1 = atoi(d["surface1"].GetString());
surface2 = atoi(d["surface2"].GetString());
surface3 = atoi(d["surface3"].GetString());
surface4 = 0;
}break;
case 4 :
{
ev1 = 1;
ev2 = 1;
ev3 = 1;
ev4 = 1;
surface1 = atoi(d["surface1"].GetString());
surface2 = atoi(d["surface2"].GetString());
surface3 = atoi(d["surface3"].GetString());
surface4 = atoi(d["surface4"].GetString());
}break;
}
cout << surface1 << endl;
//recupere tout le contenu du fichier texte afin d'avoir les donnees meteo et utilisateurs
fstream f("data.txt", fstream::in );
getline( f, s, '\0');
//ferme le fichier
f.close();
//parse la chaine de caractère json
d2.Parse(s.c_str());
//extrait les valeurs de la chaine de caractere
jDate = d2["date1"].GetString();
jEvp = d2["evp2"].GetString();
jPrecipitation = d2["precipitation1"].GetString();
cout << jDate << endl;
cout << jEvp << endl;
cout << jPrecipitation << endl;
cout << calculArrosage(surface1) <<endl;
cout << calculArrosage(surface2) <<endl;
cout << calculArrosage(surface3) <<endl;
cout << calculArrosage(surface4) <<endl;
}
void startTrame(string name, string trame, int surface, int ev)
{
// si il faut envoyer au moins un litre et que l'electrovanne est attribué
if(calculArrosage(surface) >= 1 && (ev == 1 || ev == 2 || ev == 3 || ev == 4))
{
//cree un socket et envoie la tramme
aquaclientsocket initSocket2(name,3256);
initSocket2.send(trame);
//ferme le socket
initSocket2.closeSocket();
}
}
void stopTrame(int surface, int ev)
{
//si la valeur du nombre de litre qui sont passes est egale au nombre de litre d'eau et que l'electrovanne est attribue
if((i == calculArrosage(surface) || i+1 == calculArrosage(surface)) && (ev == 1 || ev == 2 || ev == 3 || ev == 4))
{
//envoie la tramme de fermeture generale, remet le nombre de litres compte a zero, incremente la variable suivant l'electrovanne et la variable de gestion d'allumage
boost::this_thread::sleep_for(boost::chrono::seconds(3));
aquaclientsocket envoieFabien("stopTrame",3256);
envoieFabien.send("000000000");
i = 0;
e++;
cout << " e : " << e << endl;
bz = 0;
}
}
void increment ()
{
//s'occupe a chaque litre qui passe d'augmenter le nombre de litre et de voir si l'on doit eteindre une electrovanne
i ++;
std::cout << " i = " << i << std::endl;
if(e == 0)
{
boost::this_thread::sleep_for(boost::chrono::seconds(1));
stopTrame(surface1, ev1);
}
if(e == 1)
{
boost::this_thread::sleep_for(boost::chrono::seconds(1));
stopTrame(surface2, ev2);
}
if(e == 2)
{
boost::this_thread::sleep_for(boost::chrono::seconds(1));
stopTrame(surface3, ev3);
}
if(e == 3)
{
boost::this_thread::sleep_for(boost::chrono::seconds(1));
stopTrame(surface4, ev4);
}
}
void gestionAllumage()
{
//s'occupe de voir si les electrovannes devrait etre allumees
boost::this_thread::sleep_for(boost::chrono::seconds(2));
for(;;)
{
block_while_paused();
if(e == 0 && bz == 0)
{
// si electrovanne non parametre dans la configuration du site, endormir la fonction
if(ev1 == 0)
{
e = 0;
boost::this_thread::sleep_for(boost::chrono::hours(1));
}
else
{
// envoie de la trame de demarage electrovanne 1
startTrame("ev1", "110000000",surface1, ev1);
connectBdd.request("UPDATE trame SET value = '110000000' WHERE id=1;");
bz = 1;
}
}
if(e == 1 && bz == 0)
{
if(ev2 == 0)
{
e = 0;
boost::this_thread::sleep_for(boost::chrono::hours(1));
}
else
{
// envoie de la trame de demarage electrovanne 2
cout << "ok" << endl;
startTrame("ev2", "001100000",surface2, ev2);
connectBdd.request("UPDATE trame SET value = '001100000' WHERE id=1;");
bz = 1;
}
}
if(e == 2 && bz == 0)
{
if(ev3 == 0)
{
e = 0;
boost::this_thread::sleep_for(boost::chrono::hours(1));
}
else
{
// envoie de la trame de demarage electrovanne 3
startTrame("ev3", "000011000",surface3, ev3);
connectBdd.request("UPDATE trame SET value = '000011000' WHERE id=1;");
bz = 1;
}
}
if(e == 3 && bz == 0)
{
if(ev4 == 0)
{
e = 0;
boost::this_thread::sleep_for(boost::chrono::hours(1));
}
else
{
// envoie de la trame de demarage electrovanne 4
startTrame("ev4", "000000110",surface4, ev4);
connectBdd.request("UPDATE trame SET value = '000000110' WHERE id=1;");
bz = 1;
boost::this_thread::sleep_for(boost::chrono::hours(1));
}
}
}
}
void pauseThread() // obligation d'initialiser un autre thread 'pauser' le thread, dans le main, cela ne marche pas, thread purement à but de test
{
int sockfd;
char buffer[MAXLINE];
struct sockaddr_in servaddr, cliaddr;
int n;
unsigned len;
std::string sBuffer;
std::cout << "Creation du server '" << "arret" << "' sur le port " << 3258 << std::endl;
// Creation du socket
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
//gestion des erreurs
perror("Echec de creation du socket");
exit(EXIT_FAILURE);
}
//Parametrages de l'alocation memoire
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Parametres du socket
servaddr.sin_family = AF_INET; // dire au socket que l'adresse est de type IPv4
servaddr.sin_addr.s_addr = INADDR_ANY; //dire qu'il accepte une connexion de n'importe quel ip
servaddr.sin_port = htons(3258); // definition du port
// "Bind" le socket a l'adresse du serveur
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
//boucle inifine
for(;;)
{
//met en place la variable de reception du message
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
//passage du contenu de la variable d'un format c a c++
sBuffer = buffer;
//affiche cette tramme
if (sBuffer == "0")
{
std::cout << "arret imediat !" << std::endl;
set_paused(true);
}
else if (sBuffer == "1")
{
std::cout << "redemarage !" << std::endl;
set_paused(false);
}
}
}
int main(int argc, char* argv[])
{
m_pause = false;
//creation des threads
boost::thread allum(&gestionAllumage);
boost::thread p1(&pauseThread);
//connexion a la base de donnees et met la valeur du nombre de litres d'eau qui ont ete utilise cette journee
//connectBdd.request("DROP TABLE IF EXISTS debit;");
//connectBdd.prep_request("INSERT INTO debit VALUES (NULL, ?);",12);
//initialise le capteur du debit d'eau
wiringPiSetupPhys();
pinMode(12,INPUT);
wiringPiISR(12,INT_EDGE_RISING, increment);
//met les electrovannes dans leur etat par defaut
aquaclientsocket initSocket("init",3256);
initSocket.send("000000000");
connectBdd.request("UPDATE trame SET value = '000000000' WHERE id=1;");
//recupere les donnees
getData();
//ajoute les threads
p1.join();
allum.join();
}