diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..716347de --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,46 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + - uses: actions/cache@v3 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '>=3.11' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + - name: Install PlatformIO Core + run: | + pip install --upgrade platformio + # It is important to first install the libraries before compiling, since otherwise compilation might fail to find the just-installed libraries + - name: Install platformIO libraries + run: pio pkg install --project-dir Mk2_3phase_RFdatalog_temp + - name: Run PlatformIO + run: | + pio run --project-dir Mk2_3phase_RFdatalog_temp diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0b2225a4..4e2506b0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,7 @@ name: "CodeQL" on: push: - # branches: [ "main" ] + branches: [ "main" ] paths: - '**.ino' - '**.cpp' @@ -22,7 +22,7 @@ on: - '**codeql.yml' pull_request: # The branches below must be a subset of the branches above - # branches: [ "main" ] + branches: [ "main" ] paths: - '**.ino' - '**.cpp' diff --git a/Mk2_3phase_RFdatalog_temp/Readme.md b/Mk2_3phase_RFdatalog_temp/Readme.md index 5a60fd36..1ae1c03c 100644 --- a/Mk2_3phase_RFdatalog_temp/Readme.md +++ b/Mk2_3phase_RFdatalog_temp/Readme.md @@ -1,6 +1,6 @@ [![en](https://img.shields.io/badge/lang-en-red.svg)](Readme.en.md) -Ce programme doit être utilisé avec l’IDE Arduino et/ou d’autres IDE de développement comme VSCode + PlatformIO. +Ce programme est conçu pour être utilisé avec l'IDE Arduino et/ou d'autres IDE de développement comme VSCode + PlatformIO. - [Utilisation avec Arduino IDE](#utilisation-avec-arduino-ide) - [Utilisation avec Visual Studio Code](#utilisation-avec-visual-studio-code) @@ -10,11 +10,11 @@ Ce programme doit être utilisé avec l’IDE Arduino et/ou d’autres IDE de d - [Configuration des sorties TRIAC](#configuration-des-sorties-triac) - [Configuration des sorties relais tout-ou-rien](#configuration-des-sorties-relais-tout-ou-rien) - [Principe de fonctionnement](#principe-de-fonctionnement) - - [Diagramme de fonctionnement](#diagramme-de-fonctionnement) - [Configuration du Watchdog](#configuration-du-watchdog) - [Configuration du ou des capteurs de température](#configuration-du-ou-des-capteurs-de-température) - - [Avec l'Arduino IDE](#avec-larduino-ide) - - [Avec Visual Studio Code et PlatformIO](#avec-visual-studio-code-et-platformio) + - [Activation de la fonctionnalité](#activation-de-la-fonctionnalité) + - [Avec l'Arduino IDE](#avec-larduino-ide) + - [Avec Visual Studio Code et PlatformIO](#avec-visual-studio-code-et-platformio) - [Configuration du ou des capteurs (commun aux 2 cas précédents)](#configuration-du-ou-des-capteurs-commun-aux-2-cas-précédents) - [Configuration de la gestion des Heures Creuses (dual tariff)](#configuration-de-la-gestion-des-heures-creuses-dual-tariff) - [Configuration matérielle](#configuration-matérielle) @@ -25,25 +25,21 @@ Ce programme doit être utilisé avec l’IDE Arduino et/ou d’autres IDE de d # Utilisation avec Arduino IDE -Vous devrez télécharger et installer la version la plus récente de l'[Arduino IDE](https://www.arduino.cc/en/software). +Pour utiliser ce programme avec l'IDE Arduino, vous devez télécharger et installer la dernière version de l'IDE Arduino. Choisissez la version "standard", PAS la version du Microsoft Store. Optez pour la version "Win 10 et plus récent, 64 bits" ou la version "MSI installer". -Téléchargez la version « standard », PAS la version du Microsoft Store. -Procurez-vous la version « Win 10 et plus récent, 64 bits » ou la version « MSI installer ». +Comme le code est optimisé avec l'une des dernières normes C++, vous devez modifier un fichier de configuration pour activer C++17. Vous trouverez le fichier '**platform.txt**' dans le chemin d'installation de l'IDE Arduino. -Étant donné que le code est optimisé avec l'une des dernières normes de C++, vous devrez modifier un fichier de configuration pour activer C++17. +Pour **Windows**, vous trouverez généralement le fichier dans '**C:\Program Files (x86)\Arduino\hardware\arduino\avr**' et/ou dans '**%LOCALAPPDATA%\Arduino15\packages\arduino\hardware\avr\x.y.z**' où **'x.y.z**' est la version du package Arduino AVR Boards. -Veuillez rechercher le fichier '**platform.txt**' situé dans le chemin d’installation de l’IDE Arduino. +Vous pouvez également exécuter cette commande dans Powershell : `Get-Childitem –Path C:\ -Include platform.txt -Recurse -ErrorAction SilentlyContinue`. Cela peut prendre quelques secondes/minutes jusqu'à ce que le fichier soit trouvé. -Pour **Windows**, typiquement, vous trouverez le fichier dans '**C:\Program Files (x86)\Arduino\hardware\arduino\avr**' et/ou dans '**%LOCALAPPDATA%\Arduino15\packages\arduino\hardware\avr\x.y.z**' où 'x.y.z' est la version du package **Arduino AVR Boards**. +Pour **Linux**, si vous utilisez le package AppImage, vous trouverez ce fichier dans '~/.arduino15/packages/arduino/hardware/avr/1.8.6'. Vous pouvez exécuter `find / -name platform.txt 2>/dev/null` au cas où l'emplacement aurait changé. -Vous pouvez aussi taper cette commande dans unPowershell : `Get-Childitem –Path C:\ -Include platform.txt -Recurse -ErrorAction SilentlyContinue`. Cela peut prendre quelques secondes/minutes jusqu’à ce que le fichier soit trouvé. +Pour **MacOSX**, ce fichier se trouve dans '/Users/[user]/Library/Arduino15/packages/arduino/hardware/avr/1.8.6'. -Pour **Linux**, si vous utilisez le paquetAppImage, vous trouverez ce fichier dans '**~/.arduino15/packages/arduino/hardware/avr/1.8.6**'. -Vous pouvez exécuter `find / -name platform.txt 2>/dev/null` au cas où l’emplacement aurait été modifié. +Ouvrez le fichier dans n'importe quel éditeur de texte (vous aurez besoin des droits d'administrateur) et remplacez le paramètre '**-std=gnu++11**' par '**-std=gnu++17**'. C'est tout ! -Modifiez le fichier dans n’importe quel éditeur de texte (vous aurez besoin des **droits d’administrateur**) et remplacez le paramètre '**-std=gnu++11**' par '**-std=gnu++17**'. Voilà ! - -Si votre Arduino IDE a été ouvert, veuillez fermer toutes les instances et l’ouvrir à nouveau. +Si votre IDE Arduino était ouvert, veuillez fermer toutes les instances et le rouvrir. # Utilisation avec Visual Studio Code @@ -90,14 +86,16 @@ Ces valeurs par défaut doivent être déterminées pour assurer un fonctionneme # Configuration du programme -D'une manière générale, la configuration d'une fonctionnalité nécessite 2 changements au moins : -- activation de la fonctionnalité en question -- configuration de la fonctionnalité en question +La configuration d'une fonctionnalité suit généralement deux étapes : +- Activation de la fonctionnalité +- Configuration des paramètres de la fonctionnalité -La pertinence de l'ensemble est validée lors de la compilation. Ainsi, si par mégarde, une *pin* est allouée 2 fois par exemple, le compilateur émettra une erreur. +La cohérence de la configuration est vérifiée lors de la compilation. Par exemple, si une *pin* est allouée deux fois par erreur, le compilateur générera une erreur. ## Configuration des sorties TRIAC -Il faudra dans un 1ᵉʳ temps définir le nombre de sorties TRIAC. + +La première étape consiste à définir le nombre de sorties TRIAC : + ```cpp inline constexpr uint8_t NO_OF_DUMPLOADS{ 2 }; ``` @@ -111,30 +109,35 @@ inline constexpr uint8_t loadPrioritiesAtStartup[NO_OF_DUMPLOADS]{ 0, 1 }; ## Configuration des sorties relais tout-ou-rien Les sorties relais tout-ou-rien permettent d'alimenter des appareils qui contiennent de l'électronique (pompe à chaleur …). -Pour chaque relais, il faut définir 5 paramètres : -- numéro de **pin** sur laquelle est branché le relais -- **seuil de surplus** avant mise en route (par défaut **1000 W**) -- **seuil d'import** avant arrêt (par défaut **200 W**) -- **durée de fonctionnement minimale** en minutes (par défaut **5 min**) -- **durée d'arrêt minimale** en minutes (par défaut **5 min**). +Il faudra activer la fonctionnalité comme ceci : +```cpp +inline constexpr bool RELAY_DIVERSION{ true }; +``` + +Chaque relais nécessite la définition de cinq paramètres : +- le numéro de **pin** sur laquelle est branché le relais +- le **seuil de surplus** avant mise en route (par défaut **1000 W**) +- le **seuil d'import** avant arrêt (par défaut **200 W**) +- la **durée de fonctionnement minimale** en minutes (par défaut **5 min**) +- la **durée d'arrêt minimale** en minutes (par défaut **5 min**). -Exemple : +Exemple de configuration d'un relais : ```cpp inline constexpr RelayEngine relays{ { { 4, 1000, 200, 10, 10 } } }; ``` -Cette ligne définit ainsi un relais câblé sur la *pin* **4**, qui se déclenchera à partir de **1000 W** de surplus, et qui s'arrêtera à partir de **200 W** d'import et dont le temps de fonctionnement mais aussi d'arrêt seront de **10 min**. +Dans cet exemple, le relais est connecté sur la *pin* **4**, il se déclenchera à partir de **1000 W** de surplus, s'arrêtera à partir de **200 W** d'import, et a une durée minimale de fonctionnement et d'arrêt de **10 min**. -Si plusieurs relais sont présents, on listera tout simplement les configurations de chaque relais de cette façon : +Pour configurer plusieurs relais, listez simplement les configurations de chaque relais : ```cpp inline constexpr RelayEngine relays{ { { 4, 1000, 200, 10, 10 }, { 3, 1500, 250, 5, 15 } } }; ``` -Les relais seront mis en route dans le même ordre que dans la liste. L'ordre d'arrêt sera l'inverse. -Dans tous les cas, les consignes de durée de fonctionnement et d'arrêt seront respectées. +Les relais sont activés dans l'ordre de la liste, et désactivés dans l'ordre inverse. +Dans tous les cas, les durées minimales de fonctionnement et d'arrêt sont toujours respectées. ### Principe de fonctionnement -Les valeurs de surplus ainsi que d'import sont calculées selon une moyenne mobile pondérée exponentiellement (**EWMA** pour **E**xponentially **W**eighted **M**oving **A**verage). -Par défaut, cette moyenne prend en compte une fenêtre d'environ 10 min. +Les seuils de surplus et d'import sont calculés en utilisant une moyenne mobile pondérée exponentiellement (EWMA), dans notre cas précis, il s'agit d'une modification d'une moyenne mobile triple exponentiellement pondérée (TEMA). +Par défaut, cette moyenne est calculée sur une fenêtre d'environ **10 min**. Vous pouvez ajuster cette durée pour l'adapter à vos besoins. Il est possible de la rallonger mais aussi de la raccourcir. Pour des raisons de performances de l'Arduino, la durée choisie sera arrondie à une durée proche qui permettra de faire les calculs sans impacter les performances du routeur. @@ -147,8 +150,16 @@ ___ Attention au suffixe '**_i**' après le nombre *15* ! ___ -### Diagramme de fonctionnement -À venir... +Les relais configurés dans le système sont gérés par un système similaire à une machine à états. +Chaque seconde, le système augmente la durée de l'état actuel de chaque relais et procède avec tous les relais en fonction de la puissance moyenne actuelle : +- si la puissance moyenne actuelle est supérieure au seuil d'import, elle essaie d'éteindre certains relais. +- si la puissance moyenne actuelle est supérieure au seuil de surplus, elle essaie d'allumer plus de relais. + +Les relais sont traités dans l'ordre croissant pour le surplus et dans l'ordre décroissant pour l'importation. + +Pour chaque relais, la transition ou le changement d'état est géré de la manière suivante : +- si le relais est *OFF* et que la puissance moyenne actuelle est inférieure au seuil de surplus, le relais essaie de passer à l'état *ON*. Cette transition est soumise à la condition que le relais ait été *OFF* pendant au moins la durée *minOFF*. +- si le relais est *ON* et que la puissance moyenne actuelle est supérieure au seuil d'importation, le relais essaie de passer à l'état *OFF*. Cette transition est soumise à la condition que le relais ait été *ON* pendant au moins la durée *minON*. ## Configuration du Watchdog Un chien de garde, en anglais *watchdog*, est un circuit électronique ou un logiciel utilisé en électronique numérique pour s'assurer qu'un automate ou un ordinateur ne reste pas bloqué à une étape particulière du traitement qu'il effectue. @@ -168,40 +179,39 @@ inline constexpr uint8_t watchDogPin{ 9 }; ## Configuration du ou des capteurs de température Il est possible de brancher un ou plusieurs capteurs de température Dallas DS18B20. -Ces capteurs peuvent être utilisés de façon purement informative mais aussi pour le contrôle de la marche forcée. +Ces capteurs peuvent servir à des fins informatives ou pour contrôler le mode de fonctionnement forcé. Pour activer cette fonctionnalité, il faudra procéder différemment selon que l'on utilise l'Arduino IDE ou Visual Studio Code avec l'extension PlatformIO. -### Avec l'Arduino IDE -If faudra activer la ligne : -```cpp -//#define TEMP_ENABLED -``` -en supprimant le commentaire, comme ceci : +### Activation de la fonctionnalité + +Pour activer cette fonctionnalité, la procédure diffère selon que vous utilisez l'Arduino IDE ou Visual Studio Code avec l'extension PlatformIO. + +#### Avec l'Arduino IDE +Activez la ligne suivante en supprimant le commentaire : ```cpp #define TEMP_ENABLED ``` -Si la bibliothèque *OneWire* n'est pas encore installée, il faudra procéder à son installation : -- Menu **Outils**=>**Gérer les bibliothèques...** -- Taper "Onewire" dans le champ de recherche -- Installer "**OneWire** par Jim Studt, ..." en version **2.3.7** ou plus récente. +Si la bibliothèque *OneWire* n'est pas installée, installez-la via le menu **Outils** => **Gérer les bibliothèques…**. +Recherchez "Onewire" et installez "**OneWire** par Jim Studt, …" en version **2.3.7** ou plus récente. -### Avec Visual Studio Code et PlatformIO -Dans ce cas, il faudra sélectionner la configuration "**env:temperature (Mk2_3phase_RFdatalog_temp)**". +#### Avec Visual Studio Code et PlatformIO +Sélectionnez la configuration "**env:temperature (Mk2_3phase_RFdatalog_temp)**". ### Configuration du ou des capteurs (commun aux 2 cas précédents) -Pour configurer le ou les capteurs, il faudra saisir leur·s adresse·s. -Pour cela, il faudra utiliser un programme qui permettra de scanner les capteurs connectés. Ce genre de programme est disponible un peu partout sur Internet mais aussi parmi les croquis d'exemple fournis avec l'Arduino IDE. -Il est conseillé de noter l'adresse de chaque capteur sur une étiquette adhésive que l'on collera sur le câble du capteur correspondant. +Pour configurer les capteurs, vous devez entrer leurs adresses. +Utilisez un programme pour scanner les capteurs connectés. +Vous pouvez trouver de tels programmes sur Internet ou parmi les exemples fournis avec l'Arduino IDE. +Il est recommandé de coller une étiquette avec l'adresse de chaque capteur sur son câble. -Les adresses seront alors saisies de la façon suivante : +Entrez les adresses comme suit : ```cpp inline constexpr TemperatureSensing temperatureSensing{ 4, { { 0x28, 0xBE, 0x41, 0x6B, 0x09, 0x00, 0x00, 0xA4 }, { 0x28, 0x1B, 0xD7, 0x6A, 0x09, 0x00, 0x00, 0xB7 } } }; ``` -Le nombre *4* en 1ᵉʳ paramètre est la *pin* que l'utilisateur aura choisi pour le bus OneWire. +Le nombre *4* en premier paramètre est la *pin* que l'utilisateur aura choisi pour le bus *OneWire*. ___ **_Note_** @@ -215,8 +225,8 @@ Cela permet par exemple de limiter la chauffe en marche forcée afin de ne pas t Cette limite peut être en durée ou en température (nécessite d'utiliser un capteur de température Dallas DS18B20). ### Configuration matérielle -Il faudra décâbler la commande du contacteur Jour/Nuit, il ne servira plus à rien. -Ensuite, il conviendra de relier *directement* une *pin* choisie au contact sec incorporé dans le compteur (bornes C1 et C2). +Décâblez la commande du contacteur Jour/Nuit, qui n'est plus nécessaire. +Reliez directement une *pin* choisie au contact sec du compteur (bornes *C1* et *C2*). ___ **__ATTENTION__** Il faut relier **directement**, une paire *pin/masse* avec les bornes *C1/C2* du compteur. @@ -224,16 +234,16 @@ Il NE doit PAS y avoir de 230 V sur ce circuit ! ___ ### Configuration logicielle -Cette fonctionnalité s'active via la ligne : +Activez la fonctionnalité comme suit : ```cpp inline constexpr bool DUAL_TARIFF{ true }; ``` -Il faudra aussi choisir le *pin* sur laquelle est relié le compteur : +Configurez la *pin* sur laquelle est relié le compteur : ```cpp inline constexpr uint8_t dualTariffPin{ 3 }; ``` -Il faudra aussi la durée en *heures* de la période d'Heures Creuses (pour l'instant, une seule période est supportée par jour)  : +Configurez la durée en *heures* de la période d'Heures Creuses (pour l'instant, une seule période est supportée par jour) : ```cpp inline constexpr uint8_t ul_OFF_PEAK_DURATION{ 8 }; ``` @@ -243,34 +253,36 @@ Enfin, on définira les modalités de fonctionnement pendant la période d'Heure inline constexpr pairForceLoad rg_ForceLoad[NO_OF_DUMPLOADS]{ { -3, 2 } }; ``` Il est possible de définir une configuration pour chaque charge indépendamment l'une des autres. -Le 1ᵉʳ paramètre détermine la temporisation de démarrage par rapport au début de la période d'Heures Creuses ou la fin de cette période  : +Le premier paramètre de *rg_ForceLoad* détermine la temporisation de démarrage par rapport au début ou à la fin des Heures Creuses : - si le nombre est positif et inférieur à 24, il s'agit du nombre d'heures, - si le nombre est négatif supérieur à −24, il s'agit du nombre d'heures par rapport à la fin des Heures Creuses - si le nombre est positif et supérieur à 24, il s'agit du nombre de minutes, - si le nombre est négatif inférieur à −24, il s'agit du nombre de minutes par rapport à la fin des Heures Creuses -Le 2ᵉ paramètre détermine la durée de la marche forcée : +Le deuxième paramètre détermine la durée de la marche forcée : - si le nombre est inférieur à 24, il s'agit du nombre d'heures, - si le nombre est supérieur à 24, il s'agit du nombre de minutes. -Prenons quelques exemples pour mieux comprendre (avec début d'HC à 23:00, jusqu'à 7:00 soit 8 h de durée) : -- ```{ -3, 2 }``` signifie démarrage **3 heures AVANT** la fin de période (à 4 h du matin), pour une durée de 2 h. -- ```{ 3, 2 }``` signifie démarrage **3 heures APRÈS** la début de période (à 2 h du matin), pour une durée de 2 h. -- ```{ -150, 2 }``` signifie démarrage **150 minutes AVANT** la fin de période (à 4:30), pour une durée de 2 h. -- ```{ 3, 180 }``` signifie démarrage **3 heures APRÈS** la début de période (à 2 h du matin), pour une durée de 180 min. +Exemples pour mieux comprendre (avec début d'HC à 23:00, jusqu'à 7:00 soit 8 h de durée) : +- ```{ -3, 2 }``` : démarrage **3 heures AVANT** la fin de période (à 4 h du matin), pour une durée de 2 h. +- ```{ 3, 2 }``` : démarrage **3 heures APRÈS** le début de période (à 2 h du matin), pour une durée de 2 h. +- ```{ -150, 2 }``` : démarrage **150 minutes AVANT** la fin de période (à 4:30), pour une durée de 2 h. +- ```{ 3, 180 }``` : démarrage **3 heures APRÈS** le début de période (à 2 h du matin), pour une durée de 180 min. -Dans le cas où l'on désire une durée *infinie* (donc jusqu'à la fin de la période d'HC), il faudra écrire par exemple : -- ```{ -3, UINT16_MAX }``` signifie démarrage **3 heures AVANT** la fin de période (à 4 h du matin) avec marche forcée jusqu'à la fin de période d'HC. +Pour une durée *infinie* (donc jusqu'à la fin de la période d'HC), utilisez ```UINT16_MAX``` comme deuxième paramètre : +- ```{ -3, UINT16_MAX }``` : démarrage **3 heures AVANT** la fin de période (à 4 h du matin) avec marche forcée jusqu'à la fin de période d'HC. -Dans un système comprenant 2 sorties (```NO_OF_DUMPLOADS``` aura alors une valeur de 2), si l'on souhaite une marche forcée uniquement sur la 2ᵉ sortie, on écrira : +Si votre système est constitué 2 sorties (```NO_OF_DUMPLOADS``` aura alors une valeur de 2), et que vous souhaitez une marche forcée uniquement sur la 2ᵉ sortie, écrivez : ```cpp inline constexpr pairForceLoad rg_ForceLoad[NO_OF_DUMPLOADS]{ { 0, 0 }, { -3, 2 } }; ``` ## Rotation des priorités -Lorsqu'on alimente un chauffe-eau triphasé, il peut être judicieux de permuter les priorités de mise en route de chaque résistance toutes les 24 h. -Ainsi, en moyenne sur plusieurs semaines, chaque résistance aura fonctionné à peu près la même durée. +La rotation des priorités est utile lors de l'alimentation d'un chauffe-eau triphasé. +Elle permet d'équilibrer la durée de fonctionnement des différentes résistances sur une période prolongée. + +Mais elle peut aussi être intéressante si on veut permuter les priorités de deux appareils chaque jour (deux chauffe-eau, …). Une fois n'est pas coutume, l'activation de cette fonction possède 2 modes : - **automatique**, on spécifiera alors @@ -282,36 +294,36 @@ inline constexpr RotationModes PRIORITY_ROTATION{ RotationModes::AUTO }; inline constexpr RotationModes PRIORITY_ROTATION{ RotationModes::PIN }; ``` En mode **automatique**, la rotation se fait automatiquement toutes les 24 h. -Em mode **manuel**, il faudra définir en plus la *pin* qui permettra de déclencher une rotation : +Em mode **manuel**, vous devez également définir la *pin* qui déclenchera la rotation : ```cpp inline constexpr uint8_t rotationPin{ 10 }; ``` ## Configuration de la marche forcée Il est possible de déclencher la marche forcée (certains routeurs appellent cette fonction *Boost*) via une *pin*. -On peut y relier un micro-interrupteur, une minuterie (ATTENTION, PAS de 230 V sur cette ligne), ou n'importe quel autre contact sec. +On peut y relier un micro-interrupteur, une minuterie (ATTENTION, PAS de 230 V sur cette ligne), ou tout autre contact sec. -Cette fonctionnalité s'active via la ligne : +Pour activer cette fonctionnalité, utilisez le code suivant : ```cpp inline constexpr bool OVERRIDE_PIN_PRESENT{ true }; ``` -Il faudra aussi choisir le *pin* sur laquelle est relié le contact sec : +Vous devez également spécifier la *pin* à laquelle le contact sec est connecté : ```cpp inline constexpr uint8_t forcePin{ 11 }; ``` ## Arrêt du routage -Il peut être utile de stopper le routage lors d'une absence de plusieurs jours. -Cela est d'autant plus intéressant si la *pin* de commande est reliée à un contact sec lui-même télécommandable à distance et/ou via une routine Alexa ou similaire. -De cette façon, il est possible de stopper le routage pendant une absence et le remettre en route par exemple la veille ou l'avant-veille, histoire d'avoir de l'eau chaude (gratuite) au retour. +Il peut être pratique de désactiver le routage lors d'une absence prolongée. +Cette fonctionnalité est particulièrement utile si la *pin* de commande est connectée à un contact sec qui peut être contrôlé à distance, par exemple via une routine Alexa ou similaire. +Ainsi, vous pouvez désactiver le routage pendant votre absence et le réactiver un ou deux jours avant votre retour, afin de disposer d'eau chaude (gratuite) à votre arrivée. -Cette fonctionnalité s'active via la ligne : +Pour activer cette fonctionnalité, utilisez le code suivant : ```cpp inline constexpr bool DIVERSION_PIN_PRESENT{ true }; ``` -Il faudra aussi choisir la *pin* sur laquelle est relié le contact sec : +Vous devez également spécifier la *pin* à laquelle le contact sec est connecté : ```cpp inline constexpr uint8_t diversionPin{ 12 }; ``` -*doc non finie* \ No newline at end of file +*doc non finie* diff --git a/Mk2_3phase_RFdatalog_temp/dualtariff.h b/Mk2_3phase_RFdatalog_temp/dualtariff.h index f6fa53fc..baa8fce1 100644 --- a/Mk2_3phase_RFdatalog_temp/dualtariff.h +++ b/Mk2_3phase_RFdatalog_temp/dualtariff.h @@ -29,7 +29,6 @@ class _rg_OffsetForce { public: constexpr _rg_OffsetForce() - : _rg() { constexpr uint16_t uiPeakDurationInSec{ OffPeakDuration * 3600 }; // calculates offsets for force start and stop of each load @@ -51,13 +50,13 @@ class _rg_OffsetForce } } } - const uint32_t (&operator[](uint8_t i) const)[2] + const auto (&operator[](uint8_t i) const) { return _rg[i]; } private: - uint32_t _rg[N][2]; + uint32_t _rg[N][2]{}; }; inline uint32_t ul_TimeOffPeak; /**< 'timestamp' for start of off-peak period */ diff --git a/Mk2_3phase_RFdatalog_temp/movingAvg.h b/Mk2_3phase_RFdatalog_temp/movingAvg.h index a0ba6da8..d6db41b6 100644 --- a/Mk2_3phase_RFdatalog_temp/movingAvg.h +++ b/Mk2_3phase_RFdatalog_temp/movingAvg.h @@ -143,7 +143,7 @@ class movingAvg return _ar[idx]; } - constexpr uint8_t getSize() const + [[nodiscard]] constexpr uint8_t getSize() const { return DURATION_IN_MINUTES; } diff --git a/Mk2_3phase_RFdatalog_temp/platformio.ini b/Mk2_3phase_RFdatalog_temp/platformio.ini index be41c038..a143f375 100644 --- a/Mk2_3phase_RFdatalog_temp/platformio.ini +++ b/Mk2_3phase_RFdatalog_temp/platformio.ini @@ -25,9 +25,10 @@ build_unflags = extra_scripts = pre:inject_sketch_name.py check_tool = cppcheck, clangtidy check_flags = - cppcheck: --enable=all - clangtidy: --fix --checks=*,-llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,-clang-diagnostic-c++17-extensions + cppcheck: --enable=all --std=c++17 --suppress=missingIncludeSystem + clangtidy: --fix --extra-arg=-std=c++17 --checks=*,-llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,-clang-diagnostic-c++17-extensions,-llvm-header-guard check_skip_packages = yes +check_src_filters = +<*> monitor_filters = default ; Remove typical terminal control codes from input time ; Add timestamp with milliseconds for each new line diff --git a/Mk2_3phase_RFdatalog_temp/processing.cpp b/Mk2_3phase_RFdatalog_temp/processing.cpp index d4b3d790..56f9a0cb 100644 --- a/Mk2_3phase_RFdatalog_temp/processing.cpp +++ b/Mk2_3phase_RFdatalog_temp/processing.cpp @@ -16,8 +16,6 @@ #include "processing.h" #include "utils_pins.h" -int32_t l_DCoffset_V[NO_OF_PHASES]; /**< <--- for LPF */ - // Define operating limits for the LP filters which identify DC offset in the voltage // sample streams. By limiting the output range, these filters always should start up // correctly. @@ -25,6 +23,8 @@ constexpr int32_t l_DCoffset_V_min{ (512L - 100L) * 256L }; /**< mid-point of AD constexpr int32_t l_DCoffset_V_max{ (512L + 100L) * 256L }; /**< mid-point of ADC plus a working margin */ constexpr int16_t i_DCoffset_I_nom{ 512L }; /**< nominal mid-point value of ADC @ x1 scale */ +int32_t l_DCoffset_V[NO_OF_PHASES]; /**< <--- for LPF */ + constexpr uint32_t WORKING_ZONE_IN_JOULES{ 3600UL }; /**< number of joule for 1Wh */ /**< main energy bucket for 3-phase use, with units of Joules * SUPPLY_FREQUENCY */ @@ -182,6 +182,9 @@ void initializeOptionalPins() } } +#if !defined(__DOXYGEN__) +void updatePortsStates() __attribute__((optimize("-O3"))); +#endif /** * @brief update the control ports for each of the physical loads * @@ -232,18 +235,18 @@ void updatePortsStates() */ void updatePhysicalLoadStates() { - uint8_t i{ 0 }; - if constexpr (PRIORITY_ROTATION != RotationModes::OFF) { if (b_reOrderLoads) { const auto temp{ loadPrioritiesAndState[0] }; - for (i = 0; i < NO_OF_DUMPLOADS - 1; ++i) + uint8_t i{ NO_OF_DUMPLOADS - 1 }; + do { - loadPrioritiesAndState[i] = loadPrioritiesAndState[i + 1]; - } - loadPrioritiesAndState[i] = temp; + loadPrioritiesAndState[i] = loadPrioritiesAndState[i - 1]; + --i; + } while (i); + loadPrioritiesAndState[0] = temp; b_reOrderLoads = false; } @@ -262,11 +265,13 @@ void updatePhysicalLoadStates() } const bool bDiversionOff{ b_diversionOff }; - for (i = 0; i < NO_OF_DUMPLOADS; ++i) + uint8_t idx{ NO_OF_DUMPLOADS }; + do { - const auto iLoad{ loadPrioritiesAndState[i] & loadStateMask }; - physicalLoadState[iLoad] = !bDiversionOff && (b_overrideLoadOn[iLoad] || (loadPrioritiesAndState[i] & loadStateOnBit)) ? LoadStates::LOAD_ON : LoadStates::LOAD_OFF; - } + --idx; + const auto iLoad{ loadPrioritiesAndState[idx] & loadStateMask }; + physicalLoadState[iLoad] = !bDiversionOff && (b_overrideLoadOn[iLoad] || (loadPrioritiesAndState[idx] & loadStateOnBit)) ? LoadStates::LOAD_ON : LoadStates::LOAD_OFF; + } while (idx); } /** @@ -334,9 +339,7 @@ void confirmPolarity(const uint8_t phase) return; } - ++count[phase]; - - if (count[phase] > PERSISTENCE_FOR_POLARITY_CHANGE) + if (++count[phase] > PERSISTENCE_FOR_POLARITY_CHANGE) { count[phase] = 0; polarityConfirmed[phase] = polarityOfMostRecentSampleV[phase]; @@ -610,8 +613,7 @@ uint8_t nextLogicalLoadToBeRemoved() uint8_t index{ NO_OF_DUMPLOADS }; do { - --index; - if (loadPrioritiesAndState[index] & loadStateOnBit) + if (loadPrioritiesAndState[--index] & loadStateOnBit) { return (index); } @@ -736,10 +738,12 @@ void processPlusHalfCycle(const uint8_t phase) void processRawSamples(const uint8_t phase) { // The raw V and I samples are processed in "phase pairs" + const auto &lastPolarity{ polarityConfirmedOfLastSampleV[phase] }; + if (Polarities::POSITIVE == polarityConfirmed[phase]) { // the polarity of this sample is positive - if (Polarities::POSITIVE != polarityConfirmedOfLastSampleV[phase]) + if (Polarities::POSITIVE != lastPolarity) { // This is the start of a new +ve half cycle, for this phase, just after the zero-crossing point. if (beyondStartUpPeriod) @@ -763,13 +767,13 @@ void processRawSamples(const uint8_t phase) else { // the polarity of this sample is negative - if (Polarities::NEGATIVE != polarityConfirmedOfLastSampleV[phase]) + if (Polarities::NEGATIVE != lastPolarity) { // This is the start of a new -ve half cycle (just after the zero-crossing point) processMinusHalfCycle(phase); } } -} // end of processRawSamples() +} /** * @brief Process the current voltage raw sample for the specific phase diff --git a/Mk2_3phase_RFdatalog_temp/type_traits.hpp b/Mk2_3phase_RFdatalog_temp/type_traits.hpp index ccacb696..eb78cf69 100644 --- a/Mk2_3phase_RFdatalog_temp/type_traits.hpp +++ b/Mk2_3phase_RFdatalog_temp/type_traits.hpp @@ -10,7 +10,7 @@ */ // ArduinoJson - https://arduinojson.org -// Copyright © 2014-2023, Benoit BLANCHON +// Copyright © 2014-2024, Benoit BLANCHON // MIT License #pragma once diff --git a/Mk2_3phase_RFdatalog_temp/type_traits/is_convertible.hpp b/Mk2_3phase_RFdatalog_temp/type_traits/is_convertible.hpp index d50754b0..843039cc 100644 --- a/Mk2_3phase_RFdatalog_temp/type_traits/is_convertible.hpp +++ b/Mk2_3phase_RFdatalog_temp/type_traits/is_convertible.hpp @@ -25,10 +25,10 @@ struct is_convertible static int probe(To); static char probe(...); - static From& _from; + static From& from_; -public: - static const bool value = sizeof(probe(_from)) == sizeof(int); + public: + static const bool value = sizeof(probe(from_)) == sizeof(int); }; #ifdef _MSC_VER #pragma warning(pop) diff --git a/Mk2_3phase_RFdatalog_temp/utils.h b/Mk2_3phase_RFdatalog_temp/utils.h index 9af32807..9483c5d2 100644 --- a/Mk2_3phase_RFdatalog_temp/utils.h +++ b/Mk2_3phase_RFdatalog_temp/utils.h @@ -132,7 +132,6 @@ inline void printConfiguration() DBUGLN(F("is present")); relays.printConfiguration(); - relays.printConfiguration(); } else { diff --git a/Mk2_3phase_RFdatalog_temp/utils_dualtariff.h b/Mk2_3phase_RFdatalog_temp/utils_dualtariff.h index 556e995b..5acef526 100644 --- a/Mk2_3phase_RFdatalog_temp/utils_dualtariff.h +++ b/Mk2_3phase_RFdatalog_temp/utils_dualtariff.h @@ -37,11 +37,11 @@ class pairForceLoad { } - constexpr int16_t getStartOffset() const + [[nodiscard]] constexpr int16_t getStartOffset() const { return iStartOffset; } - constexpr uint16_t getDuration() const + [[nodiscard]] constexpr uint16_t getDuration() const { return uiDuration; } diff --git a/Mk2_3phase_RFdatalog_temp/utils_relay.h b/Mk2_3phase_RFdatalog_temp/utils_relay.h index 9d67f84c..cc9e9955 100644 --- a/Mk2_3phase_RFdatalog_temp/utils_relay.h +++ b/Mk2_3phase_RFdatalog_temp/utils_relay.h @@ -14,7 +14,6 @@ #include "types.h" #include "type_traits.hpp" -#include "type_traits.hpp" #include "config_system.h" #include "movingAvg.h" @@ -37,7 +36,7 @@ class relayOutput * @param _relay_pin Control pin for the relay */ explicit constexpr relayOutput(const uint8_t _relay_pin) - : relay_pin(_relay_pin) + : relay_pin{_relay_pin} { } @@ -49,7 +48,7 @@ class relayOutput * @param _importThreshold Import threshold to turn relay OFF */ constexpr relayOutput(uint8_t _relay_pin, int16_t _surplusThreshold, int16_t _importThreshold) - : relay_pin(_relay_pin), surplusThreshold(-abs(_surplusThreshold)), importThreshold(abs(_importThreshold)) + : relay_pin{_relay_pin}, surplusThreshold{-abs(_surplusThreshold)}, importThreshold{abs(_importThreshold)} { } @@ -63,7 +62,7 @@ class relayOutput * @param _minOFF Minimum duration in minutes to leave relay OFF */ constexpr relayOutput(uint8_t _relay_pin, int16_t _surplusThreshold, int16_t _importThreshold, uint16_t _minON, uint16_t _minOFF) - : relay_pin(_relay_pin), surplusThreshold(-abs(_surplusThreshold)), importThreshold(abs(_importThreshold)), minON(_minON * 60), minOFF(_minOFF * 60) + : relay_pin{_relay_pin}, surplusThreshold{-abs(_surplusThreshold)}, importThreshold{abs(_importThreshold)}, minON{_minON * 60}, minOFF{_minOFF * 60} { } @@ -152,7 +151,7 @@ class relayOutput { return try_turnON(); } - else if (currentAvgPower > importThreshold) + if (currentAvgPower > importThreshold) { return try_turnOFF(); } @@ -256,7 +255,7 @@ class RelayEngine * @brief Construct a list of relays * */ - constexpr RelayEngine(const relayOutput (&ref)[N]) + explicit constexpr RelayEngine(const relayOutput (&ref)[N]) : relay(ref) { } @@ -298,7 +297,7 @@ class RelayEngine */ inline static auto get_average() { - return ewma_average.getAverageT(); + return ewma_average.getAverageS(); } /** diff --git a/Mk2_3phase_RFdatalog_temp/utils_temp.h b/Mk2_3phase_RFdatalog_temp/utils_temp.h index d62ce92a..9a57a4c3 100644 --- a/Mk2_3phase_RFdatalog_temp/utils_temp.h +++ b/Mk2_3phase_RFdatalog_temp/utils_temp.h @@ -23,6 +23,18 @@ inline constexpr bool TEMP_SENSOR_PRESENT{ true }; /**< set it to 'true' if temp inline constexpr bool TEMP_SENSOR_PRESENT{ false }; /**< set it to 'true' if temperature sensing is needed */ #endif +/** + * @struct DeviceAddress + * @brief Structure representing the address of a device. + * + * This structure is used to store the unique address of a device, such as a DS18B20 temperature sensor. + * The address is an array of 8 bytes, typically represented in hexadecimal. + */ +struct DeviceAddress +{ + uint8_t addr[8]; /**< The address of the device as an array of 8 bytes. */ +}; + /** * @brief This class implements the temperature sensing feature * @@ -35,12 +47,9 @@ class TemperatureSensing { using ScratchPad = uint8_t[9]; - struct DeviceAddress - { - uint8_t addr[8]; - }; - public: + constexpr TemperatureSensing() = delete; + /** * @brief Construct a new Temperature Sensing object * diff --git a/Readme.md b/Readme.md index 318b137d..2ba4dee6 100644 --- a/Readme.md +++ b/Readme.md @@ -70,13 +70,13 @@ Vous trouverez [ici](schematics/3phase_Mainboard.pdf) le schéma de la carte-mè ## Documentation de développement -Vous pouvez commencer à lire la documentation ici [3-phase diverter](https://fredm67.github.io/PVRouter-3-phase/) (en anglais). +Vous pouvez commencer à lire la documentation ici [3-phase routeur](https://fredm67.github.io/PVRouter-3-phase/) (en anglais). ## Documentation de l’utilisateur final ### Aperçu -L’objectif était de modifier/optimiser le programme pour le cas « spécial » d’un chauffe-eau triphasé. Un chauffe-eau triphasé est composé en fait de 3 éléments de chauffage indépendants. La plupart du temps, un tel chauffe-eau peut être connecté en monophasé, en triphasé étoile (WYE) ou triphasé triangle (Delta). Lorsqu’il est connecté en étoile (sans varistor), il n’y a pas besoin de fil de neutre parce que le système est équilibré, donc à tout moment, il n’y a pas de courant qui circule vers le neutre. +L’objectif était de modifier/optimiser le programme pour le cas « spécial » d’un chauffe-eau triphasé. Un chauffe-eau triphasé est composé en fait de 3 éléments de chauffage indépendants. La plupart du temps, un tel chauffe-eau peut être connecté en monophasé, en triphasé étoile (WYE) ou triphasé triangle (Delta). Lorsqu’il est connecté en étoile, il n’y a pas besoin de fil de neutre parce que le système est équilibré, donc à tout moment, il n’y a pas de courant qui circule vers le neutre. Fonctionnalités ajoutées : @@ -122,24 +122,24 @@ Les seuils de surplus et d'import sont calculés par une moyenne glissante sur u ### Capteur de température -Pour l’instant, uniquement lecture. Il sera utilisé pour optimiser la pleine puissance de la force, pour prendre la bonne décision pendant la nuit. +Il peut être utilisé pour optimiser le fonctionnement de la marche forcée, pour prendre la bonne décision pendant la nuit. ### Profil Enphase zéro export Lorsque le profil zéro-export est activé, le système PV réduit la production d’énergie si la production du système dépasse les besoins de consommation du site. Cela garantit zéro injection dans le réseau. -Comme effet secondaire, le diverteur ne verra pas à aucun moment un surplus d’énergie. -L’idée est donc d’appliquer un certain décalage à l’énergie mesurée par le diverteur. -Comme il est déjà commenté dans le code, après l'assignation d’une valeur négative à *REQUIRED_EXPORT_IN_WATTS*, le diverter agira comme un générateur PV. -Si vous définissez une valeur de *-20*, chaque fois que le diverter mesure le flux d’énergie, il ajoutera *-20* aux mesures. +Comme effet secondaire, le routeur ne verra pas à aucun moment un surplus d’énergie. +L’idée est donc d’appliquer un certain décalage à l’énergie mesurée par le routeur. +Comme il est déjà commenté dans le code, après l'assignation d’une valeur négative à *REQUIRED_EXPORT_IN_WATTS*, le routeur agira comme un générateur PV. +Si vous définissez une valeur de *-20*, chaque fois que le routeur mesure le flux d’énergie, il ajoutera *-20* aux mesures. Alors, maintenant voyons ce qui se passe dans différents cas: -- la valeur mesurée est **positive** (importation d’énergie = pas d’excédent), après avoir ajouté *-20*, cela reste positif, le diverter ne fait rien. Pour une valeur comprise entre -20 et 0, le déviateur ne fera rien non plus. +- la valeur mesurée est **positive** (importation d’énergie = pas d’excédent), après avoir ajouté *-20*, cela reste positif, le routeur ne fait rien. Pour une valeur comprise entre -20 et 0, le déviateur ne fera rien non plus. - la valeur mesurée est **autour de zéro**. Dans cette situation, la limitation du "profil zéro exportation" est active. Après l’ajout de *-20*, nous obtenons une valeur négative, ce qui déclenchera le détournement d’énergie vers le chauffe-eau. Ensuite, il y a une sorte de réaction en chaîne. L’Envoy détecte plus de consommation, décide d’augmenter la production. -À la mesure suivante, le diverter mesure à nouveau une valeur autour de zéro, ajoute à nouveau -20, et détourne encore plus d’énergie. +À la mesure suivante, le routeur mesure à nouveau une valeur autour de zéro, ajoute à nouveau -20, et détourne encore plus d’énergie. Lorsque la production (et l’excédent) arrive au maximum possible, la valeur mesurée restera autour de zéro+ et le système deviendra stable. Cela a été testé en situation réelle par Amorim. Selon chaque situation, il peut être nécessaire de modifier cette valeur de *-20* à une valeur plus grande ou plus petite. diff --git a/dev/RawSamplesTool_6chan/RawSamplesTool_6chan.ino b/dev/RawSamplesTool_6chan/RawSamplesTool_6chan.ino index b5b5a249..cfc8f56a 100644 --- a/dev/RawSamplesTool_6chan/RawSamplesTool_6chan.ino +++ b/dev/RawSamplesTool_6chan/RawSamplesTool_6chan.ino @@ -9,7 +9,7 @@ * Robin Emley (calypso_rae on Open Energy Monitor Forum) * December 2012 */ - + #define POSITIVE 1 #define NEGATIVE 0 #define ON 0 // the external trigger device is active low @@ -33,16 +33,16 @@ byte sensorPin_I3 = 5; long cycleCount = 0; int samplesRecorded = 0; -float cyclesPerSecond = 50; // use float to ensure accurate maths +float cyclesPerSecond = 50; // use float to ensure accurate maths -byte polarityNow; +byte polarityNow; boolean beyondStartUpPhase = false; byte currentStateOfTriac; -int lastSample_V1; // stored value from the previous loop (HP filter is for voltage samples only) -float lastFiltered_V1; // voltage values after HP-filtering to remove the DC offset -byte polarityOfLastSample_V1; // for zero-crossing detection - +int lastSample_V1; // stored value from the previous loop (HP filter is for voltage samples only) +float lastFiltered_V1; // voltage values after HP-filtering to remove the DC offset +byte polarityOfLastSample_V1; // for zero-crossing detection + boolean recordingNow; boolean recordingComplete; byte cycleNumberBeingRecorded; @@ -50,36 +50,35 @@ byte noOfCyclesToBeRecorded; unsigned long recordingMayStartAt; boolean firstLoop = true; -int settlingDelay = 5; // <<--- settling time (seconds) for HPF +int settlingDelay = 5; // <<--- settling time (seconds) for HPF char blankLine[82]; char newLine[82]; -int storedSample_V1[50]; -int storedSample_V2[50]; +int storedSample_V1[50]; +int storedSample_V2[50]; int storedSample_V3[50]; int storedSample_I1[50]; int storedSample_I2[50]; int storedSample_I3[50]; void setup() -{ +{ delay(3000); Serial.begin(9600); - + // initialise each character of the display line blankLine[0] = '|'; blankLine[80] = '|'; - + for (int i = 1; i < 80; i++) { blankLine[i] = ' '; } - + blankLine[40] = '.'; - + Serial.print(">>free RAM = "); Serial.println(freeRam()); // a useful value to keep an eye on - } @@ -96,74 +95,85 @@ void setup() * At the start of the following cycle, the data collected during the * previous cycle data is sent to the Serial window. */ -void loop() // each iteration of loop is for one pair of measurements only +void loop() // each iteration of loop is for one pair of measurements only { - if(firstLoop) + if (firstLoop) { unsigned long timeNow = millis(); - Serial.print ("millis() now = "); - Serial.println (timeNow); - + Serial.print("millis() now = "); + Serial.println(timeNow); + recordingMayStartAt = timeNow + (settlingDelay * 1000); - Serial.print ("recordingMayStartAt "); - Serial.println (recordingMayStartAt); - + Serial.print("recordingMayStartAt "); + Serial.println(recordingMayStartAt); + recordingNow = false; firstLoop = false; recordingComplete = false; noOfCyclesToBeRecorded = 1; cycleNumberBeingRecorded = 0; - samplesRecorded = 0; + samplesRecorded = 0; } - - int sample_V1 = analogRead(sensorPin_V1); //Read in raw voltage signal - int sample_I1 = analogRead(sensorPin_I1); //Read in raw current signal - int sample_V2 = analogRead(sensorPin_V2); //Read in raw voltage signal - int sample_I2 = analogRead(sensorPin_I2); //Read in raw current signal - int sample_V3 = analogRead(sensorPin_V3); //Read in raw current signal - int sample_I3 = analogRead(sensorPin_I3); //Read in raw current signal - float filtered_V1 = 0.996*(lastFiltered_V1 + sample_V1 - lastSample_V1); + int sample_V1 = analogRead(sensorPin_V1); //Read in raw voltage signal + int sample_I1 = analogRead(sensorPin_I1); //Read in raw current signal + int sample_V2 = analogRead(sensorPin_V2); //Read in raw voltage signal + int sample_I2 = analogRead(sensorPin_I2); //Read in raw current signal + int sample_V3 = analogRead(sensorPin_V3); //Read in raw current signal + int sample_I3 = analogRead(sensorPin_I3); //Read in raw current signal + + float filtered_V1 = 0.996 * (lastFiltered_V1 + sample_V1 - lastSample_V1); byte polarityOfThisSample_V1; - if(filtered_V1 > 0) + if (filtered_V1 > 0) { polarityOfThisSample_V1 = POSITIVE; - - if (polarityOfLastSample_V1 != POSITIVE) + + if (polarityOfLastSample_V1 != POSITIVE) { // This is the start of a new mains cycle - cycleCount++; - - if (recordingNow == true) { - if (cycleNumberBeingRecorded >= noOfCyclesToBeRecorded) { - Serial.print ("No of cycles recorded = "); - Serial.println (cycleNumberBeingRecorded); - dispatch_recorded_data(); } - else { - cycleNumberBeingRecorded++; } } - - else - if((cycleCount % 50) == 1) { - unsigned long timeNow = millis(); - if (timeNow > recordingMayStartAt) { - recordingNow = true; - cycleNumberBeingRecorded++; } - else { - Serial.println((int)(recordingMayStartAt - timeNow) / 1000); } } - } // end of specific processing for first +ve reading in each mains cycle - - } // end of specific processing of +ve cycles + cycleCount++; + + if (recordingNow == true) + { + if (cycleNumberBeingRecorded >= noOfCyclesToBeRecorded) + { + Serial.print("No of cycles recorded = "); + Serial.println(cycleNumberBeingRecorded); + dispatch_recorded_data(); + } + else + { + cycleNumberBeingRecorded++; + } + } + + else if ((cycleCount % 50) == 1) + { + unsigned long timeNow = millis(); + if (timeNow > recordingMayStartAt) + { + recordingNow = true; + cycleNumberBeingRecorded++; + } + else + { + Serial.println((int)(recordingMayStartAt - timeNow) / 1000); + } + } + } // end of specific processing for first +ve reading in each mains cycle + + } // end of specific processing of +ve cycles else { - polarityOfThisSample_V1 = NEGATIVE; - - if (polarityOfLastSample_V1 != NEGATIVE) + polarityOfThisSample_V1 = NEGATIVE; + + if (polarityOfLastSample_V1 != NEGATIVE) { // at the start of a new negative half cycle } } - + if (recordingNow == true) { storedSample_V1[samplesRecorded] = sample_V1; @@ -172,19 +182,19 @@ void loop() // each iteration of loop is for one pair of measurements only storedSample_I1[samplesRecorded] = sample_I1; storedSample_I2[samplesRecorded] = sample_I2; storedSample_I3[samplesRecorded] = sample_I3; - samplesRecorded++; + ++samplesRecorded; } - - polarityOfLastSample_V1 = polarityOfThisSample_V1; - lastSample_V1 = sample_V1; - lastFiltered_V1 = filtered_V1; -} // end of loop() + + polarityOfLastSample_V1 = polarityOfThisSample_V1; + lastSample_V1 = sample_V1; + lastFiltered_V1 = filtered_V1; +} // end of loop() void dispatch_recorded_data() -{ +{ // display raw samples via the Serial Monitor - // ------------------------------------------ + // ------------------------------------------ Serial.print("cycleCount "); Serial.print(cycleCount); @@ -200,102 +210,113 @@ void dispatch_recorded_data() int V3, I3; int min_V3 = 1023, min_I3 = 1023; int max_V3 = 0, max_I3 = 0; - - for (int index = 0; index < samplesRecorded; index++) + + for (int index = 0; index < samplesRecorded; index++) { strcpy(newLine, blankLine); - V1 = storedSample_V1[index]; - I1 = storedSample_I1[index]; - V2 = storedSample_V2[index]; - I2 = storedSample_I2[index]; - V3 = storedSample_V3[index]; - I3 = storedSample_I3[index]; - - if (V1 < min_V1){min_V1 = V1;} - if (V1 > max_V1){max_V1 = V1;} - if (I1 < min_I1){min_I1 = I1;} - if (I1 > max_I1){max_I1 = I1;} - - if (V2 < min_V2){min_V2 = V2;} - if (V2 > max_V2){max_V2 = V2;} - if (I2 < min_I2){min_I2 = I2;} - if (I2 > max_I2){max_I2 = I2;} - - if (V3 < min_V3){min_V3 = V3;} - if (V3 > max_V3){max_V3 = V3;} - if (I3 < min_I3){min_I3 = I3;} - if (I3 > max_I3){max_I3 = I3;} - - newLine[map(V1, 0, 1023, 0, 80)] = '0'; - newLine[map(I1, 0, 1023, 0, 80)] = '1'; - newLine[map(V2, 0, 1023, 0, 80)] = '2'; - newLine[map(I2, 0, 1023, 0, 80)] = '3'; - newLine[map(V3, 0, 1023, 0, 80)] = '4'; - newLine[map(I3, 0, 1023, 0, 80)] = '5'; - - if ((index % 1) == 0) // change this to "% 1" for full resolution + V1 = storedSample_V1[index]; + I1 = storedSample_I1[index]; + V2 = storedSample_V2[index]; + I2 = storedSample_I2[index]; + V3 = storedSample_V3[index]; + I3 = storedSample_I3[index]; + + if (V1 < min_V1) { min_V1 = V1; } + if (V1 > max_V1) { max_V1 = V1; } + if (I1 < min_I1) { min_I1 = I1; } + if (I1 > max_I1) { max_I1 = I1; } + + if (V2 < min_V2) { min_V2 = V2; } + if (V2 > max_V2) { max_V2 = V2; } + if (I2 < min_I2) { min_I2 = I2; } + if (I2 > max_I2) { max_I2 = I2; } + + if (V3 < min_V3) { min_V3 = V3; } + if (V3 > max_V3) { max_V3 = V3; } + if (I3 < min_I3) { min_I3 = I3; } + if (I3 > max_I3) { max_I3 = I3; } + + newLine[map(V1, 0, 1023, 0, 80)] = '0'; + newLine[map(I1, 0, 1023, 0, 80)] = '1'; + newLine[map(V2, 0, 1023, 0, 80)] = '2'; + newLine[map(I2, 0, 1023, 0, 80)] = '3'; + newLine[map(V3, 0, 1023, 0, 80)] = '4'; + newLine[map(I3, 0, 1023, 0, 80)] = '5'; + + if ((index % 1) == 0) // change this to "% 1" for full resolution { Serial.println(newLine); } } - - Serial.print("min_V1 "); Serial.print(min_V1); - Serial.print(", max_V1 "); Serial.print(max_V1); - Serial.print(", min_I1 "); Serial.print(min_I1); - Serial.print(", max_I1 "); Serial.println(max_I1); - - Serial.print("min_V2 "); Serial.print(min_V2); - Serial.print(", max_V2 "); Serial.print(max_V2); - Serial.print(", min_I2 "); Serial.print(min_I2); - Serial.print(", max_I2 "); Serial.println(max_I2); - - Serial.print("min_V3 "); Serial.print(min_V3); - Serial.print(", max_V3 "); Serial.print(max_V3); - Serial.print(", min_I3 "); Serial.print(min_I3); - Serial.print(", max_I3 "); Serial.println(max_I3); - - + + Serial.print("min_V1 "); + Serial.print(min_V1); + Serial.print(", max_V1 "); + Serial.print(max_V1); + Serial.print(", min_I1 "); + Serial.print(min_I1); + Serial.print(", max_I1 "); + Serial.println(max_I1); + + Serial.print("min_V2 "); + Serial.print(min_V2); + Serial.print(", max_V2 "); + Serial.print(max_V2); + Serial.print(", min_I2 "); + Serial.print(min_I2); + Serial.print(", max_I2 "); + Serial.println(max_I2); + + Serial.print("min_V3 "); + Serial.print(min_V3); + Serial.print(", max_V3 "); + Serial.print(max_V3); + Serial.print(", min_I3 "); + Serial.print(min_I3); + Serial.print(", max_I3 "); + Serial.println(max_I3); + + Serial.println(); Serial.println(); - - // despatch raw samples via the Serial Monitor - // ------------------------------------------- - + + // despatch raw samples via the Serial Monitor + // ------------------------------------------- + Serial.println("Raw data from stored cycle: ,[cr]"); Serial.print(samplesRecorded); Serial.println(", <<< No of sample pairs"); - for (int index = 0; index < samplesRecorded; index++) + for (int index = 0; index < samplesRecorded; index++) { - Serial.print (storedSample_V1[index]); - Serial.print(','); - Serial.println (storedSample_I1[index]); + Serial.print(storedSample_V1[index]); + Serial.print(','); + Serial.println(storedSample_I1[index]); } recordingNow = false; firstLoop = true; pause(); -} +} void pause() { byte done = false; byte dummyByte; - + while (done != true) { if (Serial.available() > 0) { - dummyByte = Serial.read(); // to 'consume' the incoming byte + dummyByte = Serial.read(); // to 'consume' the incoming byte if (dummyByte == 'g') done++; } - } + } } -int freeRam () { - extern int __heap_start, *__brkval; - int v; - return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +int freeRam() +{ + extern int __heap_start, *__brkval; + int v; + return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); } - - diff --git a/dev/cal_CTx_v_meter/platformio.ini b/dev/cal_CTx_v_meter/platformio.ini index 50d8f819..8f12e9e4 100644 --- a/dev/cal_CTx_v_meter/platformio.ini +++ b/dev/cal_CTx_v_meter/platformio.ini @@ -28,6 +28,7 @@ check_flags = cppcheck: --enable=all clangtidy: --fix --checks=*,-llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,-clang-diagnostic-c++17-extensions check_skip_packages = yes +check_src_filters = +<*> monitor_filters = default ; Remove typical terminal control codes from input time ; Add timestamp with milliseconds for each new line diff --git "a/docs/Carte-m\303\250re.drawio" "b/docs/Carte-m\303\250re.drawio" index 42a98cd6..e3842026 100644 --- "a/docs/Carte-m\303\250re.drawio" +++ "b/docs/Carte-m\303\250re.drawio" @@ -1,133 +1,241 @@ - + - + - - - - - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - + - - + + - + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git "a/docs/Carte-m\303\250re.pdf" "b/docs/Carte-m\303\250re.pdf" index ebe2c0d0..eb299270 100644 Binary files "a/docs/Carte-m\303\250re.pdf" and "b/docs/Carte-m\303\250re.pdf" differ diff --git a/docs/CarteACI_Mono_Autre_Routeur.drawio b/docs/CarteACI_Mono_Autre_Routeur.drawio index 3804fff9..9626e0a9 100644 --- a/docs/CarteACI_Mono_Autre_Routeur.drawio +++ b/docs/CarteACI_Mono_Autre_Routeur.drawio @@ -1,16 +1,13 @@ - + - + - - - - + - + @@ -92,13 +89,13 @@ - + - - + + @@ -184,7 +181,7 @@ - + @@ -194,43 +191,21 @@ - + - - - - - - - - - - - - + - - - - - - - - - - - @@ -249,32 +224,33 @@ - + - + - - + + - + - + - + + - + - + - + @@ -283,23 +259,11 @@ - - - - - - - - - - - - - + @@ -352,7 +316,7 @@ - + @@ -441,7 +405,7 @@ - + @@ -451,28 +415,17 @@ - + - - - - - - - - - - - - + @@ -495,12 +448,12 @@ - + - + @@ -510,9 +463,9 @@ - + - + @@ -563,20 +516,14 @@ - - - - - - - - + + - - + + @@ -654,17 +601,6 @@ - - - - - - - - - - - @@ -696,15 +632,15 @@ - + - - - - + + + + @@ -793,17 +729,6 @@ - - - - - - - - - - - @@ -837,9 +762,9 @@ - + - + @@ -891,55 +816,44 @@ - + - + - + - + - + - + - - - - - - - - - - - - + - + @@ -948,7 +862,7 @@ - + @@ -967,7 +881,7 @@ - + @@ -981,18 +895,7 @@ - - - - - - - - - - - - + @@ -1015,46 +918,23 @@ - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - - - - + + + + @@ -1063,27 +943,292 @@ - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/CarteACI_Mono_Autre_Routeur.pdf b/docs/CarteACI_Mono_Autre_Routeur.pdf index f4a92988..8d3fb811 100644 Binary files a/docs/CarteACI_Mono_Autre_Routeur.pdf and b/docs/CarteACI_Mono_Autre_Routeur.pdf differ diff --git a/docs/SortieRelais.drawio b/docs/SortieRelais.drawio index 9a1d18b8..5717681b 100644 --- a/docs/SortieRelais.drawio +++ b/docs/SortieRelais.drawio @@ -1,6 +1,6 @@ - + - + @@ -10,16 +10,16 @@ - + - + - + - + @@ -35,7 +35,7 @@ - + @@ -44,7 +44,7 @@ - + @@ -55,7 +55,7 @@ - + @@ -67,12 +67,15 @@ - + - + + + + diff --git a/docs/SortieRelais.pdf b/docs/SortieRelais.pdf index e40352ae..898b8179 100644 Binary files a/docs/SortieRelais.pdf and b/docs/SortieRelais.pdf differ