-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathSolar_Router_V15_10.ino
More file actions
1695 lines (1538 loc) · 68.6 KB
/
Solar_Router_V15_10.ino
File metadata and controls
1695 lines (1538 loc) · 68.6 KB
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
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#define Version "15.10"
#define HOSTNAME "RMS-ESP32-"
#define CLE_Rom_Init 912567899 //Valeur pour tester si ROM vierge ou pas. Un changement de valeur remet à zéro toutes les données. / Value to test whether blank ROM or not.
/*
PV Router / Routeur Photovoltaïque
****************************************
RMS=Routeur Multi Sources
Choix de 10 sources différentes pour lire la consommation électrique en entrée de maison
- lecture de la tension avec un transformateur et du courant avec une sonde ampèremétrique (UxI)
- lecture des données du Linky (Linky)
- module (JSY-MK-194T) intégrant une mesure de tension secteur et 2 sondes ampèremétriques (UxIx2)
- module (JSY-MK-333) pour une installation triphasé
- Lecture passerelle Enphase - Envoy-S metered (firmware V5 et V7,V8)
- Lecture avec Shelly Em
- Lecture avec Shelly Pro Em
- Lecture compteur SmartG
- Lecture compteur HomeWizard
- Lecture via MQTT
- Lecture depuis un autre ESP depuis une des sources citées plus haut
En option une à 4 mesures de température en interne (DS18B20), en externe ou via MQTT est possible.
Historique des versions
- V9.00_RMS
Stockage des températures avec une décimale
Simplification changement de nom de réseau WIFI
Choix mode Wifi avec ou sans veille
Sélection source de température
Source de puissance reçue via MQTT
Souscription MQTT à une température externe
Souscription MQTT pour forcer On ou Off les actionneurs.
- V9.01_RMS fonctionne avec la bibliothèque ESP32 Version 2.0.17
Validation Pva_valide pour les Linky en CACSI
- V9.02_RMS fonctionne avec la bibliothèque ESP32 V 3.01 .
Suite au passage de la bibliothèque ESP32 en Version 3.01 importants changement pour le routeur sur le WIFI, les Timers, Le Watchdog et la partition mémoire FLASH.
Attention à ne pas utiliser la bibliothèque ESP32 en Version 3.00, elle est bugée et génère 20% de plus de code.
Filtrage des températures pour tolérer une perte éventuelle de mesure
- V9.03_RMS
Suite au changement de bibliothèque ESP32 en V3.0.1, le scan réseau pour un changement de nom de WIFI ne fonctionnait plus. Scan fait maintenant au boot.
- V10.00
OTA par le Web directement en complément de l'Arduino IDE
Modification des calculs de puissance en UxIx3 pour avoir une représentation similaire au Linky (Merci PhDV61)
Modification de la surveillance Watchdog
- V11.00
Possibilité de définir le SSID et le mot de passe du Wifi par le port série
Import / Export des paramètres et actions
Relance découverte MQTT toutes les 5mn
Re-écriture de la surveillance par watchdog suite au changement de bibliothèque 3.0.x carte ESP32
Estimation temps equivalent d'ouverture max du Triac et relais cumulée depuis 6h du matin. Prise en compte de la puissance en sin² du mode découpe
Correction d'un bug de syntaxe non détecté par le compilateur depuis la version V9 affectant les communications d'un ESP esclave vers le maître
Affichage de l'occupation RAM
- V11.10
Nouvelle source de mesure Shelly Pro Em
- V11.11
Correction bug mesure de température distante
- V11.12
Correction bug mesure données Shelly Em suite évolution bibliothèque ESP32 V3.0.2
- V11.13
Correction bug sur export des paramètres
- V11.14
Correction bug choix sortie 0V ou 3.3V actif
- V11.15
Correction bug sur export des paramètres
- V11.16
Modification pour pouvoir faire des imports de paramètres avec Firefox
- V11.17
Compilation avec la nouvelle version 3.03 de la carte ESP32
- V11.18
Recherche de la couleur Tempo non plus chez EDF mais RTE (sauf pour senseur Linky)
Améliorations UxIx3
- V11.19
Nouvelle adresse de recherche Tempo chez RTE (sauf pour senseur Linky) plus simple
Compilation avec la bibliothèque V3.0.4 pour l'ESP32
- V11.20
Compilation avec la bibliothèque V3.1.0-RC1 pour l'ESP32
- V12.00
Jusqu'à 4 capteurs de température DS18B20 ou extérieurs
Offset sur les températures si besoin de corriger les mesures
Rajout d'informations en sortie MQTT
Les Actions peuvent être conditionnées à l'état d'autres Actions sur le même ESP32 ou un distant
RAZ des historiques sur demande
- V12.01
Correction bug sur les dixièmes de degrés des températures
- V12.03
Corrections sur les multiplications et divisions de float par une constante
- V12.04
Mise à jour Shelly Em Pro
Clarification mise en page Actions
- V12.05
Correction bugs Duree_Relais dans Mqtt.ino et débordement micros() dans Source_UxI.ino
- V12.06
Compilation avec une partition mémoire NoFS suite à comportement anormal du watchdog.
- V13.00
Compilation à faire avec une partition mémoire NoFS.
Conditionnement Actions par d'autres actions différentes pour chaque tranche horaire.
Introduction Mot de passe/Clé d'accès pour modifier les paramètres ou actions
MQTT: un prefixe pour la déclaration et un autre pour la publication de l'état
Si Action inactive arrêt envoi commande Off sur relais distant.
Création d'une hysteresis sur les température si Tinf<Tsup
Choix de la connexion, WIFI avec Internet, WIFI sans internet ou pas de WIFI (mode AP)
Retrait du watchdog. Il ne fonctionne plus, sauf si on retire des lignes de code sur des sujets qui n'ont rien à voir. Problème occupation/débordement mémoire ? Pas clair.
Choix des couleurs sur les pages Web
Choix de l'horloge :internet,Linky,Interne ou Secteur
Choix paramétrage en mode standard ou expert.
- V13.01
Mystère du watchdog qui fait planter les ESP esclaves après quelques minutes, bien que plus présent. Il faut lui dire de ne pas s'activer avec un esp_task_wdt_deinit(); en début de programme
RAZ du JSY-MK-194 quand on demande un RAZ dans la page paramètre
Enrichissement des messages MQTT pour l'option Linky avec les énergies par index.
- V13.02
Rajout delai de 100ms après RAZ du JSY-MK-194
Correction Shelly Pro Em
- V13.03
Bug corrigé : variable non initialisée en l'abscence de Triac
Mise en cache du navigateur (5mn) de certaines pages pour accélerer le chargement
- V14
Carte ESP32 Wroom avec écran 320*240
Envoi température CPU en MQTT
Notes mesurant la qualité des échanges entre ESP32
Correction bug calcul Energie avec Horloge Linky
- V14.01
Correction bug MesurePower UxI
- V14.02
Re-introduction du Watchdog avec une table de partition personalisé fichier : partitions.csv
Correction bug absence lecture état actions
- V14.03
Forcer l'affichage normal, non miroir sur l'écran. Selection automatique de l'écran
- V14.04
Modif pour Shelly Pro Em ligne 245
Retrait mode miroir pour les écrans
- V14.10
Modif pour Shelly Pro Em de Dash
Introduction ESP32-ETH01 : Ethernet
- V4.11
Prise en compte des chips model D0WDQ6 qui fonctionne en WiFi bien que non V3
- V14.20
Possibilité de remplacer les 2 LEDs par un mini écran SSD1306,SSD1309 ou SH1106
Augmentation de la taille de l'identifiant ESP32 MQTT
Source HomeWizard
Correction Nom serveur si Ethernet
- V14.21
Shelly Em Gen3
Courbe sur 10mn des ouvertures de Triac ou SSR
Choix d'affichage des courbes de VA
RAZ pour JSY-MK-333G
- V14.22
Distintinction des ESP32U en version "ESP32-D0WD" et WT-ETH01 (Ethernet)
- V14.23
MQTT : envoi facteur de puissance sans unité et envoi STGE du Linky
- V14.24
Bug affichage ouverture action 2s
Bug affichage puissance HomeWizard. Modif ValJsonSG().
- V14.25
Affichage des autres routeurs en page d'accueil
- V15.00
Retrait température CPU dans les données brutes. Plus défini par Espressif
Reaction plus dynamique à choisir dans le cas d'un CACSI et légère surproduction
Si source de données de puissance externe, le nom du routeur s'affiche en plus de l'IP
Correction décodage Smart Gateway ValJsonSG
Choix durée allumage écran LCD
Affichage des puissances Max du jour
Sortie au format PWM pour les Actions
Choix du Timeout en cas de coupure de la communication
Pilotage des Actions par MQTT : tOnOff,Mode,SeuilOn,SeuilOff,OuvreMax,Periode (Topic=DeviceName/Nom_Action)
Favicon
- V15.01
Nettoyage code html, javascript,css (Merci Michy)
Connexion Wifi :extension du timeout et 2 tentatives avant de déclarer une erreur (Merci Lolo69)
- V15.02
Modifications proposée par Lolo69 sur les connexions WIFI avec le Shelly
Rajout du nom du routeur dans le titre des pages HTML
- V15.03
Arrêt par stop() de toutes les connexions WIFI comme proposé par Lolo69
- V15.04
Correction conflit Wifi/OLed
Fin message Shelly non plus sur Timeout mais chaine de caractères. A vérifier avec tous les modèles de Shelly. Codage d'après ChatGPT
- V15.05
Si plusieurs AP même SSID, choix du niveau le plus élevé
Telnet port 23 identique au port série USB si liaison ethernet/wifi
- V15.06
Correction affichage IP
- V15.07
Modif lecture Shelly Em
- V15.08
Possibilité de trouver le réseau WIFI par WPS. Modif proposée par SR19
Amélioretion renouvellement token Enphase proposée par SR19
Création d'une source de puissance non définie pour la première mise en route
- V15.09
Estimateur injection proposé par Ludovic35
- V15.10
Modification recurrence sortie MQTT pour accepter 1s
Affichage adresse IPV6
Les détails sont disponibles sur / Details are available here:
https://f1atb.fr Section Domotique / Home Automation
F1ATB Septembre 2025
GNU Affero General Public License (AGPL) / AGPL-3.0-or-later
Arduino IDE 2.3.5
Espressif ESP V3.3.0
Compilation avec Partition Scheme : custom ou No FS ou minimal SPIFFS
Library used:
Utilisation de la bibliothèque WiFi version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\WiFi
Utilisation de la bibliothèque Networking version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\Network
Utilisation de la bibliothèque NetworkClientSecure version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\NetworkClientSecure
Utilisation de la bibliothèque ESPmDNS version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\ESPmDNS
Utilisation de la bibliothèque WebServer version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\WebServer
Utilisation de la bibliothèque FS version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\FS
Utilisation de la bibliothèque ArduinoOTA version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\ArduinoOTA
Utilisation de la bibliothèque Update version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\Update
Utilisation de la bibliothèque PubSubClient version 2.8 dans le dossier: Arduino\Sketchbooks\libraries\PubSubClient
Utilisation de la bibliothèque EEPROM version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\EEPROM
Utilisation de la bibliothèque OneWire version 2.3.8 dans le dossier: Arduino\Sketchbooks\libraries\OneWire
Utilisation de la bibliothèque DallasTemperature version 4.0.3 dans le dossier: Arduino\Sketchbooks\libraries\DallasTemperature
Utilisation de la bibliothèque UrlEncode version 1.0.1 dans le dossier: Arduino\Sketchbooks\libraries\UrlEncode
Utilisation de la bibliothèque EthernetESP32 version 1.0.2 dans le dossier: Arduino\Sketchbooks\libraries\EthernetESP32
Utilisation de la bibliothèque SPI version 3.3.0 dans le dossier: Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\SPI
Utilisation de la bibliothèque LovyanGFX version 1.2.9 dans le dossier: Arduino\Sketchbooks\libraries\LovyanGFX (!!! Branch develop pour IDF 5.5.0+ : https://github.com/lovyan03/LovyanGFX/tree/develop)
*/
//Librairies
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <ESPmDNS.h>
#include <WebServer.h>
#include <ArduinoOTA.h> //Modification On The Air
#include <PubSubClient.h> //Librairie pour la gestion Mqtt
#include <EEPROM.h> //Librairie pour le stockage en EEPROM historique quotidien
#include <esp_sntp.h>
#include "OneWire.h"
#include "DallasTemperature.h"
#include "UrlEncode.h"
#include <HardwareSerial.h>
#include <Update.h>
#include <esp_task_wdt.h> //Pour deinitialiser le watchdog. Nécessaire pour les gros program en ROM. Mystère non élucidé
#include <EthernetESP32.h>
#include <esp_wps.h> //Librairie WPS pour appairage automatique connexion WiFi //SR19
//Program routines
#include "pageHtmlBrute.h"
#include "pageHtmlMain.h"
#include "pageHtmlConnect.h"
#include "pageHtmlPara.h"
#include "pageHtmlActions.h"
#include "pageHtmlOTA.h"
#include "pageHtmlExport.h"
#include "pageHtmlHeure.h"
#include "pageHtmlCouleurs.h"
#include "Actions.h"
//Watchdog de 180 secondes. Le systeme se Reset si pas de dialoque avec le LINKY ou JSY-MK-194T/333 ou Enphase-Envoy pendant 180s
//Watchdog for 180 seconds. The system resets if no dialogue with the Linky or JSY-MK-194T/333 or Enphase-Envoy for 180s
#define WDT_TIMEOUT 180
#define SER_BUF_SIZE 4096
#define TEMPERATURE_PRECISION 12
//Nombre Actions Max
#define LesActionsLength 10 //Ne pas toucher -Javascript connais pas
//Nombre Routeurs réseau Max
#define LesRouteursMax 8 //Ne pas toucher -Javascript connais pas
//VARIABLES
const char *ap_default_ssid; // Mode Access point IP: 192.168.4.1
const char *ap_default_psk = NULL; // Pas de mot de passe en AP,
//Paramètres pour le stockage en ROM apres les données du RMS
unsigned long Cle_ROM;
String ssid = "";
String password = "";
String CleAcces = "";
String CleAccesRef = "";
String Source = "NotDef";
String Source_data = "NotDef";
String SerialIn = "";
String hostname = "";
byte dhcpOn = 1;
byte ModePara = 0; //0 = Minimal, 1= Expert
byte ModeReseau = 0; //0 = Internet, 1= LAN only, 2 =AP pas de réseau
byte Horloge = 0; //0=Internet, 1=Linky, 2=Interne, 3=IT 10ms/triac, 4=IT 20ms
byte ESP32_Type = 0; //0=Inconnu,1=Wroom seul,2=Wroom 1 relais,3=Wroom 4 relais,4=Wroom+Ecran320*240,10=ESP32-ETH01
byte LEDgroupe = 0; //0:pas de LED,1à9 pour les LED. 10 et 11 pour les écrans OLED
byte LEDyellow[] = { 0, 18, 4, 2, 0, 0, 0, 0, 0, 0, 18, 4, 18, 4 }; //Ou SDA pour OLED
byte LEDgreen[] = { 0, 19, 16, 4, 0, 0, 0, 0, 0, 0, 19, 32, 19, 32 }; //ou SCL pour OLED
unsigned long Gateway = 0;
unsigned long masque = 4294967040;
unsigned long dns = 0;
unsigned long RMSextIP = 0;
unsigned int MQTTRepet = 0;
unsigned long MQTTIP = 0;
unsigned int MQTTPort = 1883;
String MQTTUser = "User";
String MQTTPwd = "password";
String MQTTPrefix = "homeassistant"; // prefix obligatoire pour l'auto-discovery entre HA et Core-Mosquitto (par défaut c'est homeassistant)
String MQTTPrefixEtat = "homeassistant";
String MQTTdeviceName = "routeur_rms";
String TopicP = "PuissanceMaison";
byte subMQTT = 0;
String nomRouteur = "Routeur - RMS";
String nomSondeFixe = "Données seconde sonde";
String nomSondeMobile = "Données Maison";
String Couleurs = ""; // Couleurs pages web
byte WifiSleep = 1;
bool wifi_connectedIPV6G = false;
String STX = String((char)2); // Start transmission
String ETX = String((char)3); // End transmission
String ES = String((char)27); //ESC Separator
String FS = String((char)28); //File Separator
String GS = String((char)29); //Group Separator
String RS = String((char)30); //Record Separator
String US = String((char)31); //Unit Separator
String MessageH[10];
int idxMessage = 0;
int P_cent_EEPROM;
int cptLEDyellow = 0;
int cptLEDgreen = 0;
//Paramètres écran
byte rotation = 3;
uint16_t Calibre[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
unsigned long DurEcran = 30000;
//Paramètres électriques
bool EnergieActiveValide = false;
long EAS_T_J0 = 0;
long EAI_T_J0 = 0;
long EAS_M_J0 = 0; //Debut du jour energie active
long EAI_M_J0 = 0;
float Tension_T, Intensite_T, PowerFactor_T, Frequence;
float Tension_M, Intensite_M, PowerFactor_M;
long Energie_T_Soutiree = 0;
long Energie_T_Injectee = 0;
long Energie_M_Soutiree = 0;
long Energie_M_Injectee = 0;
long EnergieJour_T_Injectee = 0;
long EnergieJour_M_Injectee = 0;
long EnergieJour_T_Soutiree = 0;
long EnergieJour_M_Soutiree = 0;
int PuissanceS_T, PuissanceS_M, PuissanceI_T, PuissanceI_M;
int PuisMaxS_T = 0, PuisMaxS_M = 0, PuisMaxI_T = 0, PuisMaxI_M = 0;
int PVAS_T, PVAS_M, PVAI_T, PVAI_M;
float PuissanceS_T_inst, PuissanceS_M_inst, PuissanceI_T_inst, PuissanceI_M_inst;
float PVAS_T_inst, PVAS_M_inst, PVAI_T_inst, PVAI_M_inst;
float Puissance_T_moy, Puissance_M_moy;
float PVA_T_moy, PVA_M_moy;
float EASfloat = 0;
float EAIfloat = 0;
int PactConso_M, PactProd;
int16_t tabPw_Maison_5mn[600]; //Puissance Active:Soutiré-Injecté toutes les 5mn
int16_t tabPw_Triac_5mn[600];
int16_t tabTemperature_5mn[4][600];
int16_t tabPw_Maison_2s[300]; //Puissance Active: toutes les 2s
int16_t tabPw_Triac_2s[300]; //Puissance Triac: toutes les 2s
int16_t tabPva_Maison_2s[300]; //Puissance Active: toutes les 2s
int16_t tabPva_Triac_2s[300];
int8_t tabPulseSinusOn[101];
int8_t tabPulseSinusTotal[101];
int8_t tab_histo_ouverture[LesActionsLength][600];
int8_t tab_histo_2s_ouverture[LesActionsLength][300];
int16_t IdxStock2s = 0;
int16_t IdxStockPW = 0;
float PmaxReseau = 36000; //Puissance Max pour eviter des débordements
bool LissageLong = false;
bool Pva_valide = false;
//Triac
bool erreurTriac = false;
byte pTriac = 0; //index table choix Pins pour Gachette Triac & ZC
int8_t pulseTriac = 0, zeroCross = -1;
int8_t PulseT[] = { 0, 4, 22, 21, 12 };
int8_t ZeroT[] = { -1, 5, 23, 22, 14 };
//Parameters for UxI
byte AnalogIn0 = 35;
byte AnalogIn1 = 32;
byte AnalogIn2 = 33;
unsigned int CalibU = 1000; //Calibration Routeur UxI
unsigned int CalibI = 1000;
byte pUxI = 0;
byte Analog0[] = { 0, 35, 35, 34, 35 };
byte Analog1[] = { 0, 32, 32, 32, 36 };
byte Analog2[] = { 0, 33, 34, 33, 39 };
int value0;
int volt[100];
int amp[100];
float KV = 0.2083; //Calibration coefficient for the voltage. Value for CalibU=1000 at startup
float KI = 0.0642; //Calibration coefficient for the current. Value for CalibI=1000 at startup
float kV = 0.2083; //Calibration coefficient for the voltage. Corrected value
float kI = 0.0642; //Calibration coefficient for the current. Corrected value
float voltM[100]; //Voltage Mean value
float ampM[100];
//Parameters for JSY-MK-194T module
byte ByteArray[130];
long LesDatas[14];
int Sens_1, Sens_2;
bool RAZ_JSY = false;
//Parameters for JSY-MK-333 module triphasé
String MK333_dataBrute = "";
// ajout PhDV61 compteur d'énergie quotidienne soutirée et injectée comme calculées par le Linky
float Energie_jour_Soutiree = 0;
float Energie_jour_Injectee = 0;
long Temps_precedent = 0; // mesure précise du temps entre deux appels au JSY-MK-333
//Parameters for Linky
bool LFon = false;
bool EASTvalid = false;
bool EAITvalid = false;
volatile int IdxDataRawLinky = 0;
volatile int IdxBufDecodLinky = 0;
volatile char DataRawLinky[10000]; //Buffer entrée données Linky
float moyPWS = 0;
float moyPWI = 0;
float moyPVAS = 0;
float moyPVAI = 0;
float COSphiS = 1;
float COSphiI = 1;
long TlastEASTvalide = 0;
long TlastEAITvalide = 0;
String LTARF = ""; //Option tarifaire RTE
String STGE = ""; //Status Linky
String STGEt = ""; //Status Tempo uniquement RTE
String NGTF = ""; //Calendrier tarifaire
String JourLinky = "";
int16_t Int_HeureLinky = 0; //Heure interne
int16_t Int_MinuteLinky = 0;
int16_t Int_SecondeLinky = 0;
long EASF01 = 0;
long EASF02 = 0;
long EASF03 = 0;
long EASF04 = 0;
long EASF05 = 0;
long EASF06 = 0;
long EASF07 = 0;
long EASF08 = 0;
long EASF09 = 0;
long EASF10 = 0;
//Paramètres for Enphase-Envoy-Smetered
String TokenEnphase = "";
String EnphaseUser = "";
String EnphasePwd = "";
String EnphaseSerial = "0"; //Sert égalemnet au Shelly comme numéro de voie
String JsonToken = "";
String Session_id = "";
long LastwhDlvdCum = 0; //Dernière valeur cumul Wh Soutire-injecté.
float EMI_Wh = 0; //Energie entrée Maison Injecté Wh
float EMS_Wh = 0; //Energie entrée Maison Soutirée Wh
unsigned long lastTokenUpdate = 0; //interval de temps depuis dernier Token Enphase //SR19
//Paramètres for SmartGateways
String SG_dataBrute = "";
//Paramètres for HomeWizard
String HW_dataBrute = "";
//Paramètres for Shelly Em
String ShEm_dataBrute = "";
int ShEm_comptage_appels = 0;
float PwMoy2 = 0; //Moyenne voie secondsaire
float pfMoy2 = 1; //pf Voie secondaire
String Shelly_Name = "";
String Shelly_Profile = "";
//Paramètres pour puissance via MQTT
String P_MQTT_Brute = "";
float PwMQTT = 0;
float PvaMQTT = 0;
float PfMQTT = 1;
//Paramètres pour RTE
byte TempoRTEon = 0;
int LastHeureRTE = -1;
int LTARFbin = 0; //Code binaire des tarifs
//Paramètres pour Source Externe
int8_t RMSextIdx = 0;
//Actions
Action LesActions[LesActionsLength]; //Liste des actions
volatile int NbActions = 0;
byte ReacCACSI = 1;
unsigned int Fpwm = 500; // Frequence signaux PWM en Hz
//Internal Timers
unsigned long startMillis;
unsigned long previousWifiMillis;
unsigned long previousHistoryMillis;
unsigned long previousWsMillis;
unsigned long previousWiMillis;
unsigned long LastRMS_Millis;
unsigned long previousTimer2sMillis;
unsigned long previousOverProdMillis;
unsigned long previousLEDsMillis;
unsigned long previousActionMillis;
unsigned long previousTempMillis;
unsigned long previousLoop;
unsigned long previousETX;
unsigned long PeriodeProgMillis = 1000;
unsigned long T_On_seconde = 0;
float previousLoopMin = 1000;
float previousLoopMax = 0;
float previousLoopMoy = 0;
unsigned long previousTimeRMS;
float previousTimeRMSMin = 1000;
float previousTimeRMSMax = 0;
float previousTimeRMSMoy = 0;
unsigned long previousMQTTenvoiMillis;
unsigned long previousMQTTMillis;
unsigned long LastPwMQTTMillis = 0;
unsigned long PeriodeMQTTMillis = 500;
//Actions et Triac(action 0)
float RetardF[LesActionsLength]; //Floating value of retard
//Variables in RAM for interruptions
volatile unsigned long lastIT = 0;
volatile int16_t IT10ms = 0; //Interruption avant deglitch
volatile int16_t IT10ms_in = 0; //Interruption apres deglitch
volatile int16_t ITmode = 0; //IT externe Triac ou interne
volatile unsigned short CptIT = 0; //Compeur IT Triac ou 20ms;
volatile unsigned short StepIT = 1;
hw_timer_t *timer = NULL;
hw_timer_t *timer10ms = NULL;
volatile int Retard[LesActionsLength];
volatile int Actif[LesActionsLength];
volatile int PulseOn[LesActionsLength];
volatile int PulseTotal[LesActionsLength];
volatile int PulseComptage[LesActionsLength];
volatile int Gpio[LesActionsLength];
volatile int OutOn[LesActionsLength];
volatile int OutOff[LesActionsLength];
//Port Serie 2 - Remplace Serial2 qui bug
HardwareSerial MySerial(2);
byte pSerial = 0; //Choix Pin port serie
int8_t RXD2 = -1, TXD2 = -1; //Port serie
int8_t RX2_[] = { -1, 16, 26, 18, 5 };
int8_t TX2_[] = { -1, 17, 27, 19, 17 };
// Heure et Date
#define MAX_SIZE_T 80
const char *ntpServer1 = "fr.pool.ntp.org";
const char *ntpServer2 = "time.nist.gov";
String DATE = "";
String DateCeJour = ""; //Plus utilisé depuis V13
bool HeureValide = false;
int16_t HeureCouranteDeci = 0;
int16_t idxPromDuJour = 0;
int16_t Int_Heure = 0; //Heure interne
int16_t Int_Minute = 0;
int16_t Int_Seconde = 0;
unsigned short Int_Last_10Millis = 0;
//Température Capteur DS18B20
byte pTemp = 0;
byte pinTemp[] = { 0, 13, 27, 33 };
OneWire oneWire(17); //Numero de pin bidon pour le constructor en attendant affectation reel à placer au debut du setup
DallasTemperature ds18b20(&oneWire);
float temperature[4]; // 4 canaux max de températurre
int offsetTemp[4]; //erreur *100
int TemperatureValide[4];
byte canalTempExterne[4];
byte refTempIP[4];
int Nbr_DS18B20 = 0;
String Source_Temp[4];
String nomTemperature[4];
String TopicT[4];
String AllTemp = "";
//MQTT
WiFiClient MqttClient;
PubSubClient clientMQTT(MqttClient);
bool Discovered = false;
//WIFI
int16_t WIFIbug = 0;
int16_t ComSurv = 6; //Timeout sans Wifi par pas de 30s
WiFiClientSecure clientSecu;
WiFiClientSecure clientSecuRTE;
String Liste_AP = "";
uint8_t bestBSSID[6]; //Meilleur en dBm adresse MAC
//Ethernet
int16_t EthernetBug = 0;
EMACDriver driver(ETH_PHY_LAN8720, 23, 18, 16);
WebServer server(80); // Simple Web Server on port 80
// === Serveur Telnet ===
WiFiServer telnetServer(23); //Port Telnet 23
WiFiClient telnetClient;
bool dispPw = false; //Affiche Power sur serial et Telnet
bool dispAct = false; //Affiche Ouverture Actions sur serial et Telnet
// Routeurs du réseau
unsigned long RMS_IP[LesRouteursMax]; //RMS_IP[0] = adresse IP de cet ESP32
String RMS_NomEtat[LesRouteursMax];
int8_t RMS_Note[LesRouteursMax];
int8_t RMS_NbCx[LesRouteursMax];
int RMS_Noms_idx = 0;
int RMS_Datas_idx = 0;
//Adressage IP coeur0 et coeur1
byte arrIP[4];
//Multicoeur - Processeur 0 - Collecte données RMS local ou distant
TaskHandle_t Task1;
esp_err_t ESP32_ERROR;
bool PuissanceRecue = false;
int PuissanceValide = 5;
//Interruptions, Current Zero Crossing from Triac device and Internal Timer
//*************************************************************************
void IRAM_ATTR onTimer10ms() { //Interruption interne toutes 10ms
ITmode = ITmode - 1;
if (ITmode < -5) ITmode = -5;
if (ITmode < 0) GestionIT_10ms(); //IT non synchrone avec le secteur . Horloge interne
}
// Interruption du Triac Signal Zc, toutes les 10ms si Triac, toutes les 20ms si systeme redressement secteur
void IRAM_ATTR currentNull() {
IT10ms = IT10ms + 1;
if ((millis() - lastIT) > 2) { // to avoid glitch detection during 2ms
ITmode = ITmode + 3;
if (ITmode > 5) ITmode = 5;
IT10ms_in = IT10ms_in + 1;
lastIT = millis();
if (ITmode > 0) GestionIT_10ms(); //IT synchrone avec le secteur signal Zc toutes les 10ms
}
}
void GestionIT_10ms() {
CptIT = CptIT + StepIT;
for (int i = 0; i < NbActions; i++) {
switch (Actif[i]) { //valeur en RAM
case 0: //Inactif
break;
case 1: //Decoupe Sinus uniquement pour Triac
if (i == 0) {
PulseComptage[0] = 0;
digitalWrite(pulseTriac, LOW); //Stop Découpe Triac
}
break;
case 4: //PWM ne depend pas IT 10ms
break;
default: // Multi Sinus ou Train de sinus
if (Gpio[i] > 0) { //Gpio valide
if (PulseComptage[i] < PulseOn[i]) {
digitalWrite(Gpio[i], OutOn[i]);
} else {
digitalWrite(Gpio[i], OutOff[i]); //Stop
}
PulseComptage[i] = PulseComptage[i] + 1;
if (PulseComptage[i] >= PulseTotal[i]) {
PulseComptage[i] = 0;
}
}
break;
}
}
}
// Interruption Timer interne toutes les 100 micro secondes
void IRAM_ATTR onTimer() { //Interruption every 100 micro second
if (Actif[0] == 1) { // Découpe Sinus
PulseComptage[0] = PulseComptage[0] + 1;
if (PulseComptage[0] > Retard[0] && Retard[0] < 98 && ITmode > 0) { //100 steps in 10 ms
digitalWrite(pulseTriac, HIGH); //Activate Triac
} else {
digitalWrite(pulseTriac, LOW); //Stop Triac
}
}
}
/*** WPS Configurations ***/ //SR19
#define ESP_WPS_MODE WPS_TYPE_PBC //SR19
esp_wps_config_t wps_config = WPS_CONFIG_INIT_DEFAULT(ESP_WPS_MODE); //SR19
bool isGOT_IP = false; //true si IP reçue //SR19
void wpsStop() { //SR19
esp_err_t err = esp_wifi_wps_disable(); //SR19
if (err != ESP_OK) { //SR19
TelnetPrintln("WPS Disable Failed: " + String(err, HEX) + "h -> " + esp_err_to_name(err)); //SR19
} //SR19
} //SR19
//Evènements WPS/WiFi //SR19
void WiFiEvent(WiFiEvent_t event) { //SR19
switch (event) { //SR19
case ARDUINO_EVENT_WIFI_STA_START: //SR19
TelnetPrintln("WiFi Démarré en Mode Station. Attente WPS Client..."); //SR19
break; //SR19
case ARDUINO_EVENT_WIFI_STA_GOT_IP: //SR19
TelnetPrintln("WiFi : " + String(WiFi.SSID()) + " connecté via WPS!"); //SR19
ssid = (WiFi.SSID()); //Récup ssid //SR19
TelnetPrintln("Récupération IP de " + hostname + " -> " + (WiFi.localIP().toString())); //SR19
TelnetPrintln("Récupération password -> " + String(WiFi.psk())); //SR19
password = (WiFi.psk());
password.trim(); //Récup password //SR19
isGOT_IP = true; /*IP reçue*/
EcritureEnROM(); //SR19
break; //SR19
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: //SR19
TelnetPrintln("Déconnecté. Redémarrage WiFi..."); //SR19
WiFi.disconnect(); //Forçage reconnexion normale //SR19
delay(10); //SR19
WiFi.reconnect(); //SR19
delay(100); //SR19
isGOT_IP = false; //Réinitialiser l'événement si déconnecté //SR19
break; //SR19
case ARDUINO_EVENT_WPS_ER_SUCCESS: //SR19
TelnetPrintln("WPS réussi! Stop WPS et connexion vers: " + String(WiFi.SSID())); //SR19
wpsStop(); //Must disable WPS before connecting //SR19
WiFi.begin(); //Connect using credentials from WPS //SR19
break; //SR19
case ARDUINO_EVENT_WIFI_STA_CONNECTED: //SR19
TelnetPrintln("WiFi Reconnecté en Mode Station");
ssid = WiFi.SSID(); // met à jour le SSID global
password = WiFi.psk(); // met à jour le mot de passe global
password.trim(); // supprime espaces et caractères indésirables (dont \n, \r, \t) // sauvegarde dans l’EEPROM //SR19
break; //SR19
default: //SR19
break; //SR19
} //SR19
}
// SETUP
//*******
void setup() {
startMillis = millis();
previousLEDsMillis = startMillis;
//Ports Série ESP
Serial.begin(115200);
TelnetPrintln("Booting");
//Watchdog initialisation
esp_task_wdt_deinit();
// Initialisation de la structure de configuration pour la WDT
esp_task_wdt_config_t wdt_config = {
.timeout_ms = WDT_TIMEOUT * 1000, // Convertir le temps en millisecondes
.idle_core_mask = (1 << portNUM_PROCESSORS) - 1, // Bitmask of all cores, https://github.com/espressif/esp-idf/blob/v5.2.2/examples/system/task_watchdog/main/task_watchdog_example_main.c
.trigger_panic = true // Enable panic to restart ESP32
};
// Initialisation de la WDT avec la structure de configuration
ESP32_ERROR = esp_task_wdt_init(&wdt_config);
TelnetPrintln("Dernier Reset : " + String(esp_err_to_name(ESP32_ERROR)));
esp_task_wdt_add(NULL); //add current thread to WDT watch
esp_task_wdt_reset();
delay(1); //VERY VERY IMPORTANT for Watchdog Reset
for (int i = 0; i < LesActionsLength; i++) {
LesActions[i] = Action(i); //Creation objets
PulseOn[i] = 0; //1/2 sinus
PulseTotal[i] = 100;
PulseComptage[i] = 0;
Retard[i] = 100;
RetardF[i] = 100;
OutOn[i] = 1;
OutOff[i] = 0;
Gpio[i] = -1;
}
//Tableau Longueur Pulse et Longueur Trame pour Multi-Sinus de 0 à 100%
float erreur;
float vrai;
float target;
for (int I = 0; I < 101; I++) {
tabPulseSinusTotal[I] = -1;
tabPulseSinusOn[I] = -1;
target = float(I) / 100.0;
for (int T = 20; T < 101; T++) {
for (int N = 0; N <= T; N++) {
if (T % 2 == 1 || N % 2 == 0) { // Valeurs impaires du total ou pulses pairs pour éviter courant continu
vrai = float(N) / float(T);
erreur = abs(vrai - target);
if (erreur < 0.004) {
tabPulseSinusTotal[I] = T;
tabPulseSinusOn[I] = N;
N = 101;
T = 101;
}
}
}
}
}
for (int i = 0; i < LesRouteursMax; i++) {
RMS_IP[i] = 0; //IP du reseau
RMS_Note[i] = 0;
RMS_NbCx[i] = 0;
}
init_puissance();
InitTemperature();
INIT_EEPROM();
//Lecture Clé pour identifier si la ROM a déjà été initialisée
Cle_ROM = CLE_Rom_Init;
unsigned long Rcle = LectureCle();
TelnetPrintln("cle : " + String(Rcle));
if (Rcle == Cle_ROM) { // Programme déjà executé
LectureEnROM();
LectureConsoMatinJour();
} else {
RAZ_Histo_Conso();
}
TelnetPrintln("Chip Model: " + String(ESP.getChipModel()));
delay(100);
MessageCommandes();
LireSerial();
Ethernet.init(driver);
if (String(ESP.getChipModel()) == "ESP32-D0WD") { //certains ESP32U et WT32-ETH01
TelnetPrintln("\nAncien modèle d'ESP32 que l'on trouve sur les cartes Ethernet WT32-ETH01 (branchez le câble) et certains ESP32U");
if (Ethernet.begin() != 0) { //C'est une carte WT-ETH01
TelnetPrintln("Carte WT32-ETH01 qui Crash en Wifi. On force Ethernet.\n");
ESP32_Type = 10; //On force Ethernet
}
}
TelnetPrintln("InitGPIO");
delay(500);
LireSerial();
InitGPIOs();
TelnetPrintln("ESP32_Type:" + String(ESP32_Type));
delay(500);
if (ESP32_Type == 4) Ecran_Init();
IP2String(RMS_IP[0]);
// Set youRMS_IP[0]c IP address
IPAddress local_IP(arrIP[3], arrIP[2], arrIP[1], arrIP[0]);
TelnetPrint("Adresse IP en mémoire : ");
TelnetPrintln(local_IP.toString());
// Set your Gateway IP address
IP2String(Gateway);
IPAddress gateway(arrIP[3], arrIP[2], arrIP[1], arrIP[0]);
// Set your masque/subnet IP address
IP2String(masque);
IPAddress subnet(arrIP[3], arrIP[2], arrIP[1], arrIP[0]);
// Set your DNS IP address
IP2String(dns);
IPAddress primaryDNS(arrIP[3], arrIP[2], arrIP[1], arrIP[0]); //optional
IPAddress secondaryDNS(8, 8, 4, 4);
hostname = String(HOSTNAME);
uint32_t chipId = 0;
for (int i = 0; i < 17; i = i + 8) {
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
hostname += String(chipId); //Add chip ID to hostname
TelnetPrintln(hostname); //optional
bool bestWifi = false;
if (ESP32_Type == 10) { //Ethernet (avant Horloge)
PrintScroll("Lancement de la liaison Ethernet");
if (Ethernet.linkStatus() == LinkOFF) {
PrintScroll("Câble Ethernet non connecté.");
}
//Ethernet.hostname(hostname);
if (dhcpOn == 0) { //Static IP
//optional
//Adresse IP eventuelles
//optional
Ethernet.begin(local_IP, primaryDNS, gateway, subnet);
delay(100);
Ethernet.begin(local_IP, primaryDNS, gateway, subnet); //On s'y prend 2 fois. Parfois ne reussi pas au premier coup
delay(100);
StockMessage("Adresse IP Ethernet fixe : : " + Ethernet.localIP().toString());
RMS_IP[0] = String2IP(Ethernet.localIP().toString());
} else {
TelnetPrintln("Initialisation Ethernet par DHCP:");
if (Ethernet.begin()) {
StockMessage("Adresse IP Ethernet assignée par DHCP : " + Ethernet.localIP().toString());
RMS_IP[0] = String2IP(Ethernet.localIP().toString());
} else {
TelnetPrintln("Failed to configure Ethernet using DHCP");
delay(1);
}
}
} else { //ESP32 en WIFI
TelnetPrintln("Lancement du Wifi");
//Liste Wifi à faire avant connexion à un AP. Necessaire depuis biblio ESP32 3.0.1
WiFi.mode(WIFI_STA);
WiFi.disconnect();
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
bestWifi = Liste_WIFI();
TelnetPrint("Version : ");
TelnetPrintln(Version);
LireSerial();
// Configure WIFI
// **************
WiFi.hostname(hostname);
ap_default_ssid = (const char *)hostname.c_str();
// Check WiFi connection
// ... check mode
if (WiFi.getMode() != WIFI_STA) {
WiFi.mode(WIFI_STA);
delay(10);
}
}
LireSerial();
if (Horloge == 0) { //heure par Internet}
//Heure / Hour . A Mettre en priorité avant WIFI (exemple ESP32 Simple Time)
//External timer to obtain the Hour and reset Watt Hour every day at 0h
sntp_set_sync_interval(10800000); //Synchro toutes les 3h
sntp_set_time_sync_notification_cb(time_sync_notification);
//sntp_servermode_dhcp(1); Déprecié
esp_sntp_servermode_dhcp(true); //Option
configTzTime("CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", ntpServer1, ntpServer2); //Voir Time-Zone:
}
//WIFI
if (ESP32_Type < 10) {
if (ModeReseau < 2) {
TelnetPrintln("ssid:" + ssid);
TelnetPrintln("password:" + password);
if (ssid.length() > 0) {
if (dhcpOn == 0) { //Static IP
//Adresse IP eventuelles
//optional
if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
TelnetPrintln("WIFI STA Failed to configure");
}
}
StockMessage("Wifi Begin : " + ssid);
WiFi.enableIPv6(); //++ Acces depuis internet !!! voir pour ajout https://randomnerdtutorials.com/esp32-esp8266-web-server-http-authentication/
if (bestWifi) {
WiFi.begin(ssid.c_str(), password.c_str(), 0, bestBSSID); // Connexion forcée au BSSID choisi
} else {
WiFi.begin(ssid.c_str(), password.c_str());
}
WiFi.setSleep(WifiSleep);
while (WiFi.status() != WL_CONNECTED && (millis() - startMillis < 20000)) { // Attente connexion au Wifi
TelnetPrint(".");
Gestion_LEDs();
TelnetPrint(String(WiFi.status()));
LireSerial();
delay(300);
}
TelnetPrintln("");
}
}
if (WiFi.status() == WL_CONNECTED && ModeReseau < 2) {
RMS_IP[0] = String2IP(WiFi.localIP().toString());
StockMessage("Connecté par WiFi, addresse IP : " + WiFi.localIP().toString() + " or <a href='http://" + hostname + ".local' >" + hostname + ".local</a>");
} else {
/*** WPS SETUP ***/ //SR19
if (WiFi.scanNetworks() != 0 && WiFi.RSSI(0) > -83) { //WPS inutile si aucun signal WiFi > -83dBm //SR19
WiFi.disconnect(false, true); //RAZ config. //SR19
delay(100); //SR19
WiFi.mode(WIFI_AP_STA); //SR19
delay(10); //SR19
TelnetPrintln("Tentative de connexion via WPS..."); //SR19
WiFi.onEvent(WiFiEvent); //appel évènements WPS/WiFi depuis WiFiEvent(WiFiEvent_t event) //SR19
delay(10); //SR19
esp_wifi_wps_enable(&wps_config); //SR19
esp_wifi_wps_start(0); //SR19
startMillis = millis(); //SR19
while (isGOT_IP != true && (millis() - startMillis < 20000)) { //Attente évènement "GOT_IP" pour récupération: ssid, password et IP //SR19