Project tutorial
Logging 2 Electricity Smart Meters Using Arduino Nano Every

Logging 2 Electricity Smart Meters Using Arduino Nano Every © GPL3+

Data logging from two electricity meters (type "eHZ") simultaneously and store data (time and value of reading) to an SD card.

  • 2,442 views
  • 0 comments
  • 2 respects

Components and supplies

Screenshot 2019 06 14 15 28 58 udl6wzcwho
Arduino Nano Every
×1
VMA 301 RTC shield
×1
VMA 304 SD card shield
×1
Level shifter, bidirectional, 5V 3.3V
×1
IR Phototransistor, NPN, SFH309FA
×2
BC337-25 Transistor, NPN
×2
4415447
Through Hole Resistor, 220 ohm
×3
Mfr 25frf52 1m sml
Resistor 1M ohm
×2
Mfr 25fbf52 22k1 sml
Resistor 22.1k ohm
×2
Kingbright wp7113srd d image
5 mm LED: Red
×1
Led technology l03r5000q1 image
5 mm LED: Yellow
×1
45w7721 40
LED, Blue
×1
Pcb products
Custom PCB
×1
2 wire cable (phototransistor PCB)
×2
49ac3715 40
DC Power Connector, Jack
×1

Necessary tools and machines

09507 01
Soldering iron (generic)
4966285
Solder Wire, Lead Free

About this project

The story

This project describes how to log electricity consumption of 2 different consumer circuits by reading the corresponding 2 smart meters ("eHz"="elektronische Haushaltszähler") simultaneously to an SD card.

It all started wanting to get a better understanding of electricity consumption w/i our household. There are 2 smart meters, the first one tracking electricity consumption of the heat pump and a second one tracking general electricity consumption (lights, stove,...).

In the www I found a project that does this job for 1 smart meter (by Volker Wegert). However that project is using an Arduino Uno and due to its memory limitations only data of 1 smart meter can be logged. Nevertheless it gave me (I'm pretty much new to Arduino, electronics and programming) a lot of insight and ideas.

During plyaing around w/ that code I stumbled across the recently released Arduino Nano Every and thought that it should be possible to achieve logging of 2 smart meters due to its much higher memory compared to Arduino Uno.

Implementation

Hardware

Core of the project is an Arduino Nano Every.

To store the smart meter data an SD card shield (Velleman VMA 304) is used. Since the latter one operates at 3.3 V (higher voltages will probalby fry the SD card shield according to what I've found in the www) while Arduino output is at 5 V, a bidirectional level-shifter converting 3.3 V <-> 5 V is needed in between.

Finally, to store the time of data acquisition together w/ the smart meter reading, a RTC (Real Time Clock) shield (Velleman VMA 301) is used.

The reason for choosing the above mentioned shields is simply my lack of experience and knowledge of alternatives and therefore the result of searching in the www for potential candidates. In the end they have proven to do their job, nevertheless there might be other shields or components suited better.

The schematics is shown below. (Hint: In the schematic it says an Arduino Nano is used. This is due to the fact that in Fritzing PC software - which I used to draw the schematic - no Arduino Nano Every was available. This does not really matter since the pinout of both is the same.)

Comparing my schematics w/ the inputs I got from Volker Wegert's project shows that I replaced some resistors:

  • between IR phototransistor and GND: 15 kOhm --> 1 MOhm (470 kOhm also sufficient). Necessary to bring BC337(-25) transistor to achieve the necessary gain (probably because of lower gain of BC337-25 as compared to BC337-40 or maybe signal of IR sender of eHZ too weak or alingment IR sender to IR receiver not precise enough)
  • between collector of transistor and VCC: 15 kOhm --> 22 kOhm (simply due the fact that I had 22 kOhm available)

The smart meter of type "eHZ-IW8E2A5" provides so called OBIS data every few seconds via IR pulses (no trigger necessary). The OBIS data is contained in a serial data stream in SML format. Since Arduino Nano Every hardware can only handle one single serial data stream, SoftwareSerial library is used in the code to read the separate serial data stream of each of the 2 smart meters.

The IR pulses from the eHZ sender diode are recorded by IR phototransistors (SFH309FA), (inverted and) amplified by a transistor (BC337-25) and then provided to pins A0 and A1 of the Arduino Nanao Every, respectively.

The picture below shows my early version sensor head (which gave me trouble to get sufficiently precise alignment of sender diode and receiver phototransistor) and the 3D printed sensor head (for printer file see link to Stefan Weigert's SML page provided w/i the software code). Since some smart meters require a trigger to send out SML data, the smart meter as well the IR reading head offer 2 openings. For the "eHZ-IW8E2A5", however, no trigger signal is needed, so only the IR phototransistor is mounted into 1 of the holes (the left one in the picture below; the other one remains empty).

In both cases it is easy to mount the sensor head to the smart meter, since surrounding the IR diodes of the smart meter there is a metal plate. So just add approrpiate magnets to attach your sensor head to the smart meter.

Furthermore, the unamplified IR pulses are supplied to pins A6 and A7 of the Arduino Nano Every. Those signals are not needed for recording the OBIS data. However - at least to my experience - a precise positioning of the IR phototransistors in front of the IR sender diode of the eHZ is important to get "good" serial data. To achieve this I run a very simple Arduino sketch ("IR-Diode-Schaltung_Test_NanoEvery.ino") that plots (using the Arduino IDE's Serial Plotter <Shift>+<CTRL>+<L>) the unamplified signals provided to A6 and A7 as well as the amplified signals provided to A0 and A1. By cautiously moving/rotating the sensor head w/ the built-in IR phototransistor in front of the eHZ's IR sender diode signal strength can be maximized. Effect of this alignment can be seen on image below which gives typical example for bad and good signal. Similar behaviour could be observed for "bad" electrical contact between cable from sensor head and PCB (e.g., using inappropriate plugs/connectors - like I did in the beginning using terminal sockets. Meanwhile I replaced them by 3.5mm mono audio jacks, see photographs below). "Bad signal" leads to serial data w/ wrong header (so that it is not recognized as SML format) or even wrong content of the SML message.

Finally the following hint w/respect to hardware: I soldered socket terminal strips ("Buchsenleiste") to the PCB and later plugged in some of the components (especially the more delicate ones likte the Arduino Nano Every or the shields) to avoid damaging those delicate components during my soldering attempts.

The LEDs are used to be able to judge the status of the logger in case it is not possible to check what's going on by, e.g., using the Arduino IDE Serial Monitor (e.g., in case power is supplied via an external power supply and not via USB port of a computer).

  • During initialization phase (or after pressing the Arduino Nano Every's reset button) the red LED blinks 5 times at the end of the setup section in the Arduino sketch. This primarily serves to show that the red LED is functional (since it is used for other purpose later). It does however NOT proove that all parts of the setup were passed successfully.
  • During the main loop in the Arduino sketch the red LED blinks 3 times right before data is written to the SD card. This is to make sure you are not pulling out the SD card while data is written to it and thereby damaging the SD card and/or potentially loosing of data.
  • The other 2 LEDs (yellow and blue) are used to display if the last data for the respective smart meter was acquired successfully (3 times slow blinking; ~+1s ON time) or not (3 times fast blinking; ~0.25s ON time. Blinking frequency, i.e., ON/OFF time can be set in the software code). In case running this logger on battery power this might reduce operating time. So feel free to change software code according to your needs. I also could imagine to improve the software code by implementing a check if a button is pressed and only if that button was pressed the success or failure of the last data acquisition is displayed. But that's dreams of the future.

Update 2020-05-03/2020-06-09:

With respect to powering I have the following remarks:

  • During setup and optimization I was powering the hardware from my computer's USB port. This seems to be fine, i.e., a lot of successfull data acquisitions
  • After having achieved good results w/ that, i switched to powering via a 5V wall power supply. In the beginning (for some weeks) this also seemed to work pretty well. Suddenly (after optimizing the connectors to the IR phototransistors, see below) it was almost impossible to successfully acquire data (i.e., basically every SML stream acquired wass too short or otherwise corrupted, so it became impossible to get the OBIS data out of it). I have no explanation for that, because I did not change anything (at least intentionally) at the hardware level (except for the connector topic mentioned above). Maybe the wall power supply deteriorated in the meantime ? I have no proof for that, since 5V are still ok.
  • Finally I used a 6V PbAcid accumulator to power the hardware. With this, the fraction of successfully acquired data went up to >>95%... If you do so, make sure that the shields are powered by the 5V output of the Arduino (and not directly conected to supply power), since otherwise you might fry some of them by the applied 6V.
  • Meanwhile I added a voltmeter w/ display (triggered by a simple push button, i.e., w/o use of Arduino functanility). Goal was to be able to get an impression of the current voltage delivered by the PbAcid battery to prevent it from deep discharge (by manually removing the electronics and charging the battery). Schematics updated, also picture of display added.

Software

Pins used and libraries needed are documented w/i the SW code. The main challenge to me was finding a working library to operate the RTC shield (based on DS1302 clock chip). There are many libraries out there in the www, however almost any of them caused trouble. Link to where I found the working library is provided at the beginning of the sketch.

In the setup section it is possible set the time in the RTC shield for the first time the code is uploaded (search for "Uncomment in case"...) or to compensate for drift over time. After that first upload these lines should of course be again set as comments in the Arduino sketch because otherwise in case of uploading the sketch to the Arduino afterwards (e.g., you want to change the logging interval) the time woul be again set to the "old" value - which of cource deviates from the current real time.

The data is written to files w/ naming convention "########.csv" (w/ "#" being a number 0-9). Ideally I would expect to find only 1 file in between manually initiated resets. However I typically find several .csv files on my SD card. To me it seems that - for to me unknown reason - the Arduino from time to time resets itself, since a new output file name (increasing numbers) is only generated at the end of the setup section of the code. Sometimes I also find the logger somewhat stuck (what I observe is that none of the LEDs is blinking for ~>30s), so I have o reset it manually. Any explanation or solution to this is highly welcome !

Furthemore it is possible to set the logging interval (variable: "loggingInterval"). In case you use the LEDs to display successful or unseccussful data acquisition, be aware that the time for that LED blinking w/i main loop limits the shortest logging interval. This might be another reason to remove the LED blinking from the code. However this might not be a real problem since read out of the smart meter only every other minute should be sufficient (assuming typical energy consumption).

In the original code from Volker Wegert 2 checks w/ respect to integrity of the SML data were implemented (1. Header of acquired data in SML format ? 2. Buffer overflow ?). However I got still many bad readings from the smart meters (probably due to imperfection in my hardware). Examining this I found that the acquired SML data passed both checks mentioned above, however the total SML message length was very often way shorter than expected. So I added another check to make sure the smart meter reading is extracted from the SML data only in case the buffer lenght was o.k. (397 byte in my case). This might be different in your application, since as far as I understood the content of the SML protocol and therefore the extractable OBIS data is set by your MSB ("Messtellenbetreiber"), i.e., the company providing the electricity meter. How long your protocol is can be figured out easily by checking the output in the Arduino IDE's Serial Monitor (There are many Serial.print in the Arduino sketch, just play around with those).

To extract the smart meter reading I did not implement an SML parser or similar. I analysed the SML data in a spread sheet using the guide by Stefan Weigert (Link see Arduino sketch) to identify the position in the buffer where the acquired SML data is stored. This - together w/ functional hardware and good alingment of the sensor head - gives me a percentage of >>95% "good"/plausible smart meter readings. This could probably be improved by implementing another check, e.g., if the last acquired smart meter reading is only a few Wh higher than the reading before. Again, dreams of the future...

In case you upgrade/optimize the software I'd appreciate if you let me know about that.

Result

Finally let me share how my logging device looks like.

BoldItalicLinkInline CodeBlock CodeHeaderBlockquoteListImageVideoThe storyThis project describes how to log electricity consumption of 2 different consumer circuits by reading the corresponding 2 smart meters ("eHz"="elektronische Haushaltszähler") simultaneously to an SD card.It all started wanting to get a better understanding of electricity consumption w/i our household. There are 2 smart meters, the first one tracking electricity consumption of the heat pump and a second one tracking general electricity consumption (lights, stove,...).In the www I found a project that does this job for 1 smart meter (by Volker Wegert). However that project is using an Arduino Uno and due to its memory limitations only data of 1 smart meter can be logged. Nevertheless it gave me (I'm pretty much new to Arduino, electronics and programming) a lot of insight and ideas.During plyaing around w/ that code I stumbled across the recently released Arduino Nano Every and thought that it should be possible to achieve logging of 2 smart meters due to its much higher memory compared to Arduino Uno.ImplementationHardwareCore of the project is an Arduino Nano Every.To store the smart meter data an SD card shield (Velleman VMA 304) is used. Since the latter one operates at 3.3 V (higher voltages will probalby fry the SD card shield according to what I've found in the www) while Arduino output is at 5 V, a bidirectional level-shifter converting 3.3 V <-> 5 V is needed in between.Finally, to store the time of data acquisition together w/ the smart meter reading, a RTC (Real Time Clock) shield (Velleman VMA 301) is used.The reason for choosing the above mentioned shields is simply my lack of experience and knowledge of alternatives and therefore the result of searching in the www for potential candidates. In the end they have proven to do their job, nevertheless there might be other shields or components suited better.The schematics is shown below. (Hint: In the schematic it says an Arduino Nano is used. This is due to the fact that in Fritzing PC software - which I used to draw the schematic - no Arduino Nano Every was available. This does not really matter since the pinout of both is the same.)Comparing my schematics w/ the inputs I got from Volker Wegert's project shows that I replaced some resistors:between IR phototransistor and GND: 15 kOhm --> 1 MOhm (470 kOhm also sufficient). Necessary to bring BC337(-25) transistor to achieve the necessary gain (probably because of lower gain of BC337-25 as compared to BC337-40 or maybe signal of IR sender of eHZ too weak or alingment IR sender to IR receiver not precise enough)between collector of transistor and VCC: 15 kOhm --> 22 kOhm (simply due the fact that I had 22 kOhm available) The smart meter of type "eHZ-IW8E2A5" provides so called OBIS data every few seconds via IR pulses (no trigger necessary). The OBIS data is contained in a serial data stream in SML format. Since Arduino Nano Every hardware can only handle one single serial data stream, SoftwareSerial library is used in the code to read the separate serial data stream of each of the 2 smart meters.The IR pulses from the eHZ sender diode are recorded by IR phototransistors (SFH309FA), (inverted and) amplified by a transistor (BC337-25) and then provided to pins A0 and A1 of the Arduino Nanao Every, respectively.The picture below shows my early version sensor head (which gave me trouble to get sufficiently precise alignment of sender diode and receiver phototransistor) and the 3D printed sensor head (for printer file see link to Stefan Weigert's SML page provided w/i the software code). Since some smart meters require a trigger to send out SML data, the smart meter as well the IR reading head offer 2 openings. For the "eHZ-IW8E2A5", however, no trigger signal is needed, so only the IR phototransistor is mounted into 1 of the holes (the left one in the picture below; the other one remains empty).In both cases it is easy to mount the sensor head to the smart meter, since surrounding the IR diodes of the smart meter there is a metal plate. So just add approrpiate magnets to attach your sensor head to the smart meter. Furthermore, the unamplified IR pulses are supplied to pins A6 and A7 of the Arduino Nano Every. Those signals are not needed for recording the OBIS data. However - at least to my experience - a precise positioning of the IR phototransistors in front of the IR sender diode of the eHZ is important to get "good" serial data. To achieve this I run a very simple Arduino sketch ("IR-Diode-Schaltung_Test_NanoEvery.ino") that plots (using the Arduino IDE's Serial Plotter <Shift>+<CTRL>+<L>) the unamplified signals provided to A6 and A7 as well as the amplified signals provided to A0 and A1. By cautiously moving/rotating the sensor head w/ the built-in IR phototransistor in front of the eHZ's IR sender diode signal strength can be maximized. Effect of this alignment can be seen on image below which gives typical example for bad and good signal. Similar behaviour could be observed for "bad" electrical contact between cable from sensor head and PCB (e.g., using inappropriate plugs/connectors - like I did in the beginning using terminal sockets. Meanwhile I replaced them by 3.5mm mono audio jacks, see photographs below). "Bad signal" leads to serial data w/ wrong header (so that it is not recognized as SML format) or even wrong content of the SML message.Finally the following hint w/respect to hardware: I soldered socket terminal strips ("Buchsenleiste") to the PCB and later plugged in some of the components (especially the more delicate ones likte the Arduino Nano Every or the shields) to avoid damaging those delicate components during my soldering attempts.The LEDs are used to be able to judge the status of the logger in case it is not possible to check what's going on by, e.g., using the Arduino IDE Serial Monitor (e.g., in case power is supplied via an external power supply and not via USB port of a computer). During initialization phase (or after pressing the Arduino Nano Every's reset button) the red LED blinks 5 times at the end of the setup section in the Arduino sketch. This primarily serves to show that the red LED is functional (since it is used for other purpose later). It does however NOT proove that all parts of the setup were passed successfully.During the main loop in the Arduino sketch the red LED blinks 3 times right before data is written to the SD card. This is to make sure you are not pulling out the SD card while data is written to it and thereby damaging the SD card and/or potentially loosing of data.The other 2 LEDs (yellow and blue) are used to display if the last data for the respective smart meter was acquired successfully (3 times slow blinking; ~+1s ON time) or not (3 times fast blinking; ~0.25s ON time. Blinking frequency, i.e., ON/OFF time can be set in the software code). In case running this logger on battery power this might reduce operating time. So feel free to change software code according to your needs. I also could imagine to improve the software code by implementing a check if a button is pressed and only if that button was pressed the success or failure of the last data acquisition is displayed. But that's dreams of the future. Update 2020-05-03/2020-06-09:With respect to powering I have the following remarks:During setup and optimization I was powering the hardware from my computer's USB port. This seems to be fine, i.e., a lot of successfull data acquisitionsAfter having achieved good results w/ that, i switched to powering via a 5V wall power supply. In the beginning (for some weeks) this also seemed to work pretty well. Suddenly (after optimizing the connectors to the IR phototransistors, see below) it was almost impossible to successfully acquire data (i.e., basically every SML stream acquired wass too short or otherwise corrupted, so it became impossible to get the OBIS data out of it). I have no explanation for that, because I did not change anything (at least intentionally) at the hardware level (except for the connector topic mentioned above). Maybe the wall power supply deteriorated in the meantime ? I have no proof for that, since 5V are still ok.Finally I used a 6V PbAcid accumulator to power the hardware. With this, the fraction of successfully acquired data went up to >>95%... If you do so, make sure that the shields are powered by the 5V output of the Arduino (and not directly conected to supply power), since otherwise you might fry some of them by the applied 6V.Meanwhile I added a voltmeter w/ display (triggered by a simple push button, i.e., w/o use of Arduino functanility). Goal was to be able to get an impression of the current voltage delivered by the PbAcid battery to prevent it from deep discharge (by manually removing the electronics and charging the battery). Schematics updated, also picture of display added.SoftwarePins used and libraries needed are documented w/i the SW code. The main challenge to me was finding a working library to operate the RTC shield (based on DS1302 clock chip). There are many libraries out there in the www, however almost any of them caused trouble. Link to where I found the working library is provided at the beginning of the sketch. In the setup section it is possible set the time in the RTC shield for the first time the code is uploaded (search for "Uncomment in case"...) or to compensate for drift over time. After that first upload these lines should of course be again set as comments in the Arduino sketch because otherwise in case of uploading the sketch to the Arduino afterwards (e.g., you want to change the logging interval) the time woul be again set to the "old" value - which of cource deviates from the current real time.The data is written to files w/ naming convention "########.csv" (w/ "#" being a number 0-9). Ideally I would expect to find only 1 file in between manually initiated resets. However I typically find several .csv files on my SD card. To me it seems that - for to me unknown reason - the Arduino from time to time resets itself, since a new output file name (increasing numbers) is only generated at the end of the setup section of the code. Sometimes I also find the logger somewhat stuck (what I observe is that none of the LEDs is blinking for ~>30s), so I have o reset it manually. Any explanation or solution to this is highly welcome !Furthemore it is possible to set the logging interval (variable: "loggingInterval"). In case you use the LEDs to display successful or unseccussful data acquisition, be aware that the time for that LED blinking w/i main loop limits the shortest logging interval. This might be another reason to remove the LED blinking from the code. However this might not be a real problem since read out of the smart meter only every other minute should be sufficient (assuming typical energy consumption).In the original code from Volker Wegert 2 checks w/ respect to integrity of the SML data were implemented (1. Header of acquired data in SML format ? 2. Buffer overflow ?). However I got still many bad readings from the smart meters (probably due to imperfection in my hardware). Examining this I found that the acquired SML data passed both checks mentioned above, however the total SML message length was very often way shorter than expected. So I added another check to make sure the smart meter reading is extracted from the SML data only in case the buffer lenght was o.k. (397 byte in my case). This might be different in your application, since as far as I understood the content of the SML protocol and therefore the extractable OBIS data is set by your MSB ("Messtellenbetreiber"), i.e., the company providing the electricity meter. How long your protocol is can be figured out easily by checking the output in the Arduino IDE's Serial Monitor (There are many Serial.print in the Arduino sketch, just play around with those).To extract the smart meter reading I did not implement an SML parser or similar. I analysed the SML data in a spread sheet using the guide by Stefan Weigert (Link see Arduino sketch) to identify the position in the buffer where the acquired SML data is stored. This - together w/ functional hardware and good alingment of the sensor head - gives me a percentage of >>95% "good"/plausible smart meter readings. This could probably be improved by implementing another check, e.g., if the last acquired smart meter reading is only a few Wh higher than the reading before. Again, dreams of the future...In case you upgrade/optimize the software I'd appreciate if you let me know about that. ResultFinally let me share how my logging device looks like.Add an imageReorder imagesDelete this imageThat's all I have to say, folks. I hope my explanations are clear and valuable to help you in case you plan to do a similar project. In case of questions feel free to contact me. I'll do my best to answer your questions. This might take some time, though, so please don't feel offended in case of some delay.Error savingDiscard changesSaveSave and nextl I have to say, folks.

I hope my explanations are clear and valuable to help you in case you plan to do a similar project. In case of questions feel free to contact me. I'll do my best to answer your questions. This might take some time, though, so please don't feel offended in case of some delay.

Code

eHZ-IW8E2A5_EMLogger_ArdNanoEvery_TMG_06.inoArduino
/*
 * Read output of 2 electricity meters of type eHZ-IW8E2A5 and write data to SD card.
 * 
 * Written by Torsten Geppert (2020) based on ideas/parts of code from
 *   - https://www.volkszaehler.org/
 *   - and hardware / software by Volker Wegert https://sourceforge.net/p/ehzy/wiki/Hardware/
 *   - and "set_clock.ino" by Matt Sparks, 2009, http://quadpoint.org/projects/arduino-ds1302 (seems to be one of the very few FUNCTIONAL DS1302 libraries out there in the www)
 *
 * Major changes/adjustments
 * 1) Hardware modified. Replaced resistors
 *    - between IR diode and GND: 15 kOhm --> 1 MOhm (470 kOhm also sufficient). Necessary to bring BC337(-25) transistor to achieve the necessary gain (probably because of lower gain of BC337-25 as compared to BC337-40 or maybe signal of IR sender of eHZ too weak or alingment IR sender to IR receiver not precise enough
 *    - between collector of transistor and VCC: 15 kOhm --> 22 kOhm 
 * 2) w/ resepect to Volker Wegert's code:
 *   - Changes in syntax of PROGMEM related texts and corresponding array necessary (probably due to other version of IDE as compared to Volker Wegert back in in 2012)
 *   - in the end removal of parts of code (e.g piezo control),I did not use in my final code (Nevertheless, those things were really helpfull for debugging during development phase)
 * 3) Change in Arduino related Hardware  
 *   - Use Arduino Nano Every + DS1302 based RTC module and SD card shield (instead of Arduino Uno + SD card shield incl. RTC).
 *     Reason: Limitation of Arduino Uno's RAM, making code run unstable w/ already 1 electricity meter (of type eHZ-IW8E2A5). It was not possible to realize readout of 2 eHZs using Arduino UNO (at least my experience/impression)
 *     -  HW used:
 *       - RTC: VMA301 by Velleman (e.g., from https://www.conrad.de/de/p/makerfactory-echtzeit-uhr-vma301-passend-fuer-arduino-boards-arduino-arduino-uno-fayaduino-freeduino-seeeduino-1612764.html)
 *       - SD shield: VMA304 by Velleman (e.g., https://www.conrad.de/de/p/makerfactory-sd-karten-logging-shield-fuer-arduino-2-tlg-1612765.html)
 *       - Level shifter (needed to adjust output from Arduino (5V) to SD shield (3.3V). In case NOT used the SD (shield ?) card might be irreversibly damaged !!!
 * 4) Time of RTC shield can be set in section "RTC setup". Should be sufficient to do this initially (i.e., when you record your data for the first time and have to set the actual time) or in case RTC time deviates too much from real time (e.g., due to drift of oscillator in RC module due to missing temperature compensatioen or similar)
 *    see comment below "Uncomment in case current time should be written to RTC shield"
 * 5) Ouptut into 1 file, at defined interval, for two meters type eHZ-IW8E2A5. (Unfortunately - and currently not understood - sometimes data is written into several files. However, due to naming (increasing number) it is stil possible to bring those files in (temporal) order. In addition time stamp is written into file for each datapoint aacquired.
 *    Output data: OBIS Kennzahl 1.8.0 (at Position 9x16+12 = 156 of SML protocol (In buffer w/ 1st element being number 0: position 155). 4 bytes (right after HEX value "56" at position 155 ## ## ## ## ##)
 *    To understand the SML protocol (and where to find the OBIS data I was interested in) Stefan Weigerts explanation is highly appreciated: http://www.stefan-weigert.de/php_loader/sml.php
 */

/* ======================================================================================================= 
 * Include Libraries and alike
 * ======================================================================================================= */

#include <stdarg.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <SoftwareSerial.h> // Serial interfaces realized by software (to allow, e.g., reading of more than just 1 sensor/eHz)
#include <SD.h>             // e.g., to write files to SD card etc.
#include <DS1302.h>

/***************************************************************************************************
 * CONSTANTS and alike
 ***************************************************************************************************/

// Software Serial stuff =============================================================================================
// Serial Data from source 1 (IR diode of 1st eHZ)
#define IR_RX_PIN_1     A0                  // Pin 14 on Arduino Nano Every
#define IR_TX_PIN_1     A2                  // not used, but required for SoftwareSerial; Pin 16 on Arduino Nano Every
// Serial Data from source 2 (IR diode of 2nd eHZ)
#define IR_RX_PIN_2     A1                  // Pin 14 on Arduino Nano Every
#define IR_TX_PIN_2     A2                  // not used, but required for SoftwareSerial; Pin 16 on Arduino Nano Every
// Dummy software serial
#define DUMMY_RX_PIN  9                     // not connected
#define DUMMY_TX_PIN  A3                    // not connected

// SD card shield VMA304 stuff =============================================================================================
#define SD_CS_PIN     8                     // Pin for SD card selection.Typically use hardware SS pin. (Pin 10 on most Arduino boards; however pin 8=A12 on Arduino Nano Every)
#define SD_SS_PIN    10                     // ###really needed ? Check if can be deleted ###  

// RTC stuff shield VMA301 stuff ===========================================================================================
// uses Pins A3, A4, A5 on Arduino Nano Every (Physical Pins 7, 8, 9; aka ???, SDA, SCL)
const int kCePin   = 17;                    // Chip Enable
const int kIoPin   = 18;                    // Input/Output
const int kSclkPin = 19;                    // Serial Clock

// Other stuff =============================================================================================
#define loggingInterval 300000              // time between readings in milli-seconds (e.g., 5 min = 5 * 60 * 1000 = 300 000)

int numberSMLBytesRead = 0;                 // used to restart reading of SML data in case less than specified number of bytes (typically 397 for my electricity meter) read         

const int LED_WriteWarning = 4;              // Pin D4 (physical pin no. 22): LED to signalize approaching or ongoing write to SD card
const int LED_SML_Acquisition_eHZ1 = 16;     // Pin PD1 (phyiscal pin no. 10): LED to signalize status of SML data acquisition for eHZ1 (OK: flashiung @ 1Hz; NOK: flashing @4 Hz*)
const int LED_SML_Acquisition_eHZ2 = 6;      // Pin A13 (phyical pin no. 24): LED to signalize status of SML data acquisition for eHZ1 (OK: flashiung @ 1Hz; NOK: flashing @4 Hz*); for whatever reason does NOT work w/ originally intended Pin D7 (phys pin 3; AVR Pin 39)
// *frequency can be changed below to, e.g. 2 Hz by setting on time to 500
int eHZ1Blink_ON=1000;                       // time LED for eHZ1 is turned on
int eHZ2Blink_ON=1000;                       // time LED for eHZ2 is turned on 
int eHZ1Blink_OFF=250;                       // time LED for eHZ1 is turned off
int eHZ2Blink_OFF=250;                       // time LED for eHZ2 is turned off  
bool SML_DataAcquisition_eHZ1 = false;       // TRUE: SML data for eHZ1 acquired successfully; FALSE: error (e.g., buffer overflow, wrong header) during SML data acquisition for eHZ1
bool SML_DataAcquisition_eHZ2 = false;       // TRUE: SML data for eHZ2 acquired successfully; FALSE: error (e.g., buffer overflow, wrong header) during SML data acquisition for eHZ2
const int eHZ1_ID = 1;
const int eHZ2_ID = 2;
unsigned long startTime;

/**
 * size of the SML message buffer = meximum number of bytes that can be received
 */
#define SML_MSG_BUFFER_SIZE    400      // eHZ-IW8E2A5 delivers SML telegram of 396 bytes

/**
 * size of a filename (8.3 + terminating 0x00 = 13 chars)
 */
#define FILENAME_SIZE           13 

/**
 * maximum number of files that can be stored
 */
#define MAX_FILE_NUMBER   99999999

/**
 * maximum time to wait for the end of a data packet received via IR
 */
#define SERIAL_READ_TIMEOUT_MS 500

/***************************************************************************************************
 * MESSAGES
 ***************************************************************************************************/

/**
 * maximum length of a message (entire text after variable substitution!)
 */
#define MAX_MESSAGE_LENGTH        50

/**
 * message numbers
 */
#define MSG_PROGRAM_STOPPED        0
#define MSG_NEXT_FILENAME          1
#define MSG_NO_FILE_NAMES_LEFT     2
#define MSG_INIT_HARDWARE          3
#define MSG_INIT_SD_CARD           4
#define MSG_INIT_SD_CARD_ERROR     5
#define MSG_BYTE_READ              6
#define MSG_BUFFER_OVERFLOW        7
#define MSG_SERIAL_OVERFLOW        8  
#define MSG_INVALID_HEADER         9
#define MSG_FILE_OPEN_FAILED      10
#define MSG_FILE_WRITTEN          11
#define MSG_FREE_MEMORY           12
#define MSG_NUM_BYTES_READ        13

/**
 * actual message texts - caution, adapt MAX_MESSAGE_LENGTH if required!
 *                               ....+....1....+....2....+....3....+....4....+....5
 */
const char msgText00[] PROGMEM = "Program stopped.";
const char msgText01[] PROGMEM = "Next output file name is '%s'";
const char msgText02[] PROGMEM = "No more file names left";
const char msgText03[] PROGMEM = "Initializing Hardware...";
const char msgText04[] PROGMEM = "Initializing SD Card...";
const char msgText05[] PROGMEM = "SD Card initialization failed";
const char msgText06[] PROGMEM = "Read byte %02hhu from IR receiver";
const char msgText07[] PROGMEM = "Message buffer overflow";
const char msgText08[] PROGMEM = "Serial buffer overflow";
const char msgText09[] PROGMEM = "Invalid escape sequence";
const char msgText10[] PROGMEM = "Unable to open output file";
const char msgText11[] PROGMEM = "%u bytes of data written to file '%s'";
const char msgText12[] PROGMEM = "%u bytes of memory available";
const char msgText13[] PROGMEM = "%u bytes read";

/**
 * table for easier access to the message texts
 */
const char *const msgTextTable[] PROGMEM = {   
  msgText00,
  msgText01,
  msgText02,
  msgText03,
  msgText04,
  msgText05,
  msgText06,
  msgText07,
  msgText08,
  msgText09,
  msgText10,
  msgText11,
  msgText12,
  msgText13
};

/***************************************************************************************************
 * GLOBAL VARIABLES (YUCK!)
 ***************************************************************************************************/

/**
 * instance of the SoftwareSerial library to handle the IR communication
 */
SoftwareSerial mySerial_1(IR_RX_PIN_1, IR_TX_PIN_1);              // used for readout of SML data of eHZ1
SoftwareSerial mySerial_2(IR_RX_PIN_2, IR_TX_PIN_2);              // used for readout of SML data of eHZ2
SoftwareSerial dummySerial(DUMMY_RX_PIN, DUMMY_TX_PIN);

// Create a RTC DS1302 object.
DS1302 rtc(kCePin, kIoPin, kSclkPin);

/**
 * variables to keep track of the name of the next file to be written
 */
unsigned long nextFileNumber = 0;
char nextFileName[FILENAME_SIZE];

/**
 * the global buffer to store the SML message currently being read
 */
unsigned char buffer[SML_MSG_BUFFER_SIZE];

/**
 * Readings of eHZ 1 and 2 (after extraction from SML data) and corresponding timestamps
 */
unsigned long eHZ_1_Reading;                
unsigned long eHZ_2_Reading;
char eHZ_1_Reading_timeStamp[50];
char eHZ_2_Reading_timeStamp[50];

/***************************************************************************************************
 * SUBROUTINES
 ***************************************************************************************************/

/** 
 * printMessage - reads a message text from the PROGMEM, performs variable substitution and 
 *                writes the resulting text to the serial console. Use MSG_* constants for
 *                messageNumber.
 */
void printMessage(int messageNumber, ...) {
  va_list args;
  char format[MAX_MESSAGE_LENGTH];
  char buffer[MAX_MESSAGE_LENGTH];
  va_start(args, messageNumber);
  strncpy_P(format, (char*)pgm_read_word(&(msgTextTable[messageNumber])), MAX_MESSAGE_LENGTH);
  vsnprintf(buffer, MAX_MESSAGE_LENGTH, format, args);
  Serial.println(buffer);
  va_end(args);
}

/**
 * reportFreeMemory - determines the amount of free memory and logs it to the serial console.
 */
void reportFreeMemory() {
  int freeMemory;
  uint8_t * heapptr, * stackptr;
  stackptr = (uint8_t *) malloc(4);     // use stackptr temporarily
  heapptr = stackptr;                   // save value of heap pointer
  free(stackptr);                       // free up the memory again (sets stackptr to 0)
  stackptr = (uint8_t *) (SP);          // save value of stack pointer
  freeMemory = stackptr - heapptr;
  printMessage(MSG_FREE_MEMORY, freeMemory);
}  

/**
 * stop - stops program execution in a controlled fashion (endless loop).
 */
void stop() {
  printMessage(MSG_PROGRAM_STOPPED);
  while(1);
}

/**
 * findNextFileNumber - determines the number and name of the next file available. This will change
 *                      the global variables nextFileName and nextFileNumber. This routine will
 *                      stop the entire program if no free filenames can be found.
 */
void findNextFileNumber() {
  do {
    sprintf(nextFileName, "%08lu.CSV", nextFileNumber);
    if (!SD.exists(nextFileName)) {
      printMessage(MSG_NEXT_FILENAME, nextFileName);
      return;
    } else {
      nextFileNumber += 1;
      if (nextFileNumber > MAX_FILE_NUMBER) {
        printMessage(MSG_NO_FILE_NAMES_LEFT);
//        errorSound(ERR_NO_FILE_NAMES_LEFT);
        stop();
      }
    }
  } while (true); 
}

void createTimeStamp(int eHZ_Number) {
  // Get the current time and date from the chip.
  Time t = rtc.time();
  // Format the time and date and insert into the temporary buffer.
  char currDAndT_buf[50];
  snprintf(currDAndT_buf, sizeof(currDAndT_buf), "%04d-%02d-%02d %02d:%02d:%02d;",
         t.yr, t.mon, t.date,
         t.hr, t.min, t.sec);

   // assign determined timestamp to either eHZ1 or eHz2
   if ( eHZ_Number == eHZ1_ID ) {           
    for (int i = 0; i<50; i++) {
      eHZ_1_Reading_timeStamp[i]=currDAndT_buf[i];
    }
//Serial.println("eHZ_1 Timestamp copied");
   }
  if ( eHZ_Number == eHZ2_ID ) {           
    for (int i = 0; i<50; i++) {
      eHZ_2_Reading_timeStamp[i]=currDAndT_buf[i];
    }
//Serial.println("eHZ_2 Timestamp copied");
  }
}

void writeTimeAndReadingToFile() {
  File outputFile;

  outputFile = SD.open(nextFileName, FILE_WRITE); 
  if (!outputFile) {
    printMessage(MSG_FILE_OPEN_FAILED);
  }
  else {
    outputFile.print(eHZ_1_Reading_timeStamp);
    outputFile.print(eHZ_1_Reading);
    outputFile.print(";");
    outputFile.print(eHZ_2_Reading_timeStamp);
    outputFile.println(eHZ_2_Reading);

    outputFile.close();
  }
}

void getSMLData(SoftwareSerial mySoftSer, int eHZ_Number) {
  unsigned int nextBufferPosition = 0;
  unsigned long lastReadTime = 0;

   // clear the message buffer
  memset(buffer, 0, sizeof(buffer));
  
  // initialize data acquisition LEDs assuming everything is fine
  if ( eHZ_Number == eHZ1_ID ) {           // remember NO error during SML data acquisition for eHZ1
    SML_DataAcquisition_eHZ1 = true;
  }
  if ( eHZ_Number == eHZ2_ID ) {           // remember NO error during SML data acquisition for eHZ2
    SML_DataAcquisition_eHZ2 = true;
  }
 
  // remove a pending overflow flag (might have been left over from a previous run) 
  // and ensure that the SoftwareSerial library is listening
  mySoftSer.overflow();
  mySoftSer.listen();

  // wait until actual data is available
  while (!mySoftSer.available());
  // Next 2 lines ("Serial.print...") not necessary for algorithm, however might be useful for information purpose on serial monitor.
  // In addition reading of serial data SEEMs to be more stable (less errors such as "invalid escape sequence"). Maybe 
  // something like "delay(200);" might also work...
  Serial.print("Number of bytes available at SW serial:");
  Serial.println(mySoftSer.available());

  // keep reading data until either the message buffer is filled or no more data was
  // received for SERIAL_READ_TIMEOUT_MS ms
  
  lastReadTime = millis();
  while (millis() - lastReadTime < SERIAL_READ_TIMEOUT_MS) {
    if (mySoftSer.available()) {
      buffer[nextBufferPosition] = mySoftSer.read();
      lastReadTime = millis();
      if (nextBufferPosition >= SML_MSG_BUFFER_SIZE) {
        dummySerial.listen();                     // disable further IR input by switching software serial input to a dummy instance
        printMessage(MSG_BUFFER_OVERFLOW);
        
        if ( eHZ_Number == eHZ1_ID ) {           // remember error during SML data acquisition for eHZ1
          SML_DataAcquisition_eHZ1 = false;
        }
        if ( eHZ_Number == eHZ2_ID ) {           // remember error during SML data acquisition for eHZ2
          SML_DataAcquisition_eHZ2 = false;
        }       
        return;
      }
      nextBufferPosition += 1;
      numberSMLBytesRead = nextBufferPosition+1;  // used to restart reading of SML data in case less than specified number of bytes (typically 397 for my electricity meter) read
    }
  }

  // report an error if an overflow condition was encountered - the data received is useless
  // in this case :-(
  if (mySoftSer.overflow()) {
    dummySerial.listen(); // disable further IR input
    printMessage(MSG_SERIAL_OVERFLOW);
    
    if ( eHZ_Number == eHZ1_ID ) {           // remember error during SML data acquisition for eHZ1
      SML_DataAcquisition_eHZ1 = false;
    }
    if ( eHZ_Number == eHZ2_ID ) {           // remember error during SML data acquisition for eHZ2
      SML_DataAcquisition_eHZ2 = false;
    }
  }
  else {
    dummySerial.listen(); // disable further IR input
    // check the header
    printMessage(MSG_NUM_BYTES_READ, nextBufferPosition + 1);
    if (!isValidHeader()) {
      // not a valid header - notify the user...
      printMessage(MSG_INVALID_HEADER);
      // ...and empty the receiver buffer (wait for the end of the current data stream
      while (mySoftSer.available() > 0) {
        mySoftSer.read();
      }
      if ( eHZ_Number == eHZ1_ID ) {           // remember error during SML data acquisition for eHZ1
        SML_DataAcquisition_eHZ1 = false;
      }
      if ( eHZ_Number == eHZ2_ID ) {           // remember error during SML data acquisition for eHZ2
        SML_DataAcquisition_eHZ2 = false;
      }    
    }
  }
}

unsigned long getElectricityMeterReading(char SML_buff) {
  /* Returns electricity meter reading in kWh
   * Electricity meter reading (for eHZ-IW8E2A5) is represented by the five bytes at buffer positions 155-159.
   * Make those 5 bytes to 1 HEX value, convert to DEC, divide by 10 (due to sacler in eHZ), divide by 1000 to get kWh
   * However, use only lowest 4 bytes (i.e., meaningful data start at position 156). Highest number represented by these four bytes is
   * in HEX FF FF FF FF or in DEC 4294967295 (= 2^32). This would correspond to approx. 429 496 kWh.
   * Assuming an (realistic) average energy consumption of about 5000 kWh per year for the heat pump, this would allow
   * to store the meter reading for about 85 years !
   * Therefore use data type unsigned long (allows values from 0 ... 2^32-1 = 0 ... 4 294 967 295)
  */
  unsigned char EMReading_buf[4];
  unsigned long EMReading;

   // clear the EMReading buffer
  memset(EMReading_buf, 0, sizeof(EMReading_buf));

  // get 4 bytes representing the electricity meter reading and write them in opposite order to new array. Then create unsigned long.
  // Algorhithm see https://forum.arduino.cc/index.php?topic=108865.0
  for(int i=3; i>=0; i--) {
    EMReading_buf[3-i] = (buffer[156+i]);
  }
  EMReading = *((unsigned long *) (& EMReading_buf[0]));
  EMReading = EMReading/10;                               // consider scaler in SML data -> divide by 10 to get Wh
  return EMReading;
}

/**
 * isValidHeader - returns true if the global message buffer begins with a valid SML escape sequence.
 */
inline boolean isValidHeader() {
  return ((buffer[0] == 0x1b) &&
          (buffer[1] == 0x1b) &&
          (buffer[2] == 0x1b) &&
          (buffer[3] == 0x1b) &&
          (buffer[4] == 0x01) &&
          (buffer[5] == 0x01) &&
          (buffer[6] == 0x01) &&
          (buffer[7] == 0x01));
}

/**
 * for DS1302 based RTC time. Not necessarily (to be) used for 
 */
namespace {

String dayAsString(const Time::Day day) {
  switch (day) {
    case Time::kSunday: return "Sunday";
    case Time::kMonday: return "Monday";
    case Time::kTuesday: return "Tuesday";
    case Time::kWednesday: return "Wednesday";
    case Time::kThursday: return "Thursday";
    case Time::kFriday: return "Friday";
    case Time::kSaturday: return "Saturday";
  }
  return "(unknown day)";
}

}  // namespace


/***************************************************************************************************
 * MAIN ROUTINES
 ***************************************************************************************************/

/**
 * SETUP
 */
void setup() {
  // Serial communication
  // =====================================================================================================
  Serial.begin(9600);
  
  // Pin configuration
  // =====================================================================================================
  printMessage(MSG_INIT_HARDWARE);
  pinMode(IR_RX_PIN_1, INPUT);
  pinMode(IR_TX_PIN_1, OUTPUT);
  pinMode(IR_RX_PIN_2, INPUT);
  pinMode(IR_TX_PIN_2, OUTPUT);
  pinMode(SD_CS_PIN, OUTPUT);
  pinMode(SD_SS_PIN, OUTPUT);
  pinMode(DUMMY_RX_PIN, INPUT);
  pinMode(DUMMY_TX_PIN, OUTPUT);
  Serial.println("...done !");

  // Setup of diagnosis / warning LEDs
  // =====================================================================================================
  // Data acquisition diagnosis LED ( let blink 5 times to prove it's working)
  //-------------------------------------------------------------------------------------------------------
  pinMode(LED_SML_Acquisition_eHZ1, OUTPUT);
  digitalWrite(LED_SML_Acquisition_eHZ1, LOW);
  pinMode(LED_SML_Acquisition_eHZ2, OUTPUT);
  digitalWrite(LED_SML_Acquisition_eHZ2, LOW);


  // SD card setup 
  // =====================================================================================================
  Serial.println("Initializing SD card...");
  if (!SD.begin(SD_CS_PIN)) {
    printMessage(MSG_INIT_SD_CARD_ERROR);
//    errorSound(ERR_INIT_SD_CARD_ERROR);
    stop();
  }
  else {
    Serial.println("...done !");
  }

  // RTC setup
  // =====================================================================================================
  // Initialize a new chip by turning off write protection and clearing the clock halt flag. These methods needn't always be called. See the DS1302 datasheet for details.
  rtc.writeProtect(false);
  rtc.halt(false);
/*  // Uncomment in case current time should be written to RTC shield
  // Make a new time object to set the date and time and set the time
  // Format: year, moth, day, hour, minute, second, day of the week (1=Sunday))
  Time t(2020, 3, 14, 9, 12, 0, 7);
  rtc.time(t);
*/

  // Sofware Serial setup
  // =====================================================================================================
  dummySerial.begin(9600);
  mySerial_1.begin(9600);                    // eHZ sends at fix rate of 9600 Baud
  mySerial_2.begin(9600);                    // eHZ sends at fix rate of 9600 Baud
  
  // Warning LED ( let blink 5 times to proove it's working)
  //-------------------------------------------------------------------------------------------------------
  pinMode(LED_WriteWarning, OUTPUT);
  for(byte i=0; i<5; i++) {
    digitalWrite(LED_WriteWarning, HIGH);
    delay(250);
    digitalWrite(LED_WriteWarning, LOW);
    delay(250);
  }

  // determine the first file name to use
  findNextFileNumber();

}

/**
 * END of SETUP
 */

void loop() {
  // turn off all LEDs
  digitalWrite(LED_WriteWarning, LOW);
  digitalWrite(LED_SML_Acquisition_eHZ1, LOW);
  digitalWrite(LED_SML_Acquisition_eHZ2, LOW);
//  reportFreeMemory();                                       // for information purposes only

  numberSMLBytesRead = 0;
  while(numberSMLBytesRead!=397 || SML_DataAcquisition_eHZ1 == false){   // in case SML data is plausible (i.e., SML header is OK and also no buffer overflow) it still happens that eHZ reading is derived from this data. Examining this showed that in those cases typically less than 397 bytes SML data were read. This while loop/condition should prevent this.
    getSMLData(mySerial_1, eHZ1_ID);                          // get SML data from 1st electricity meter (Input: A0), store it into (global) buffer
  }
  createTimeStamp(eHZ1_ID);
  Serial.println("Time stamp eHZ_1 created...");
  eHZ_1_Reading = getElectricityMeterReading(buffer);     // extract OBIS 1.8.0. in Wh x 10 and store it in (global) variable
  Serial.print("eHZ_1 Reading: ");
  Serial.println(eHZ_1_Reading);
  
  numberSMLBytesRead = 0;
  while(numberSMLBytesRead!=397 || SML_DataAcquisition_eHZ2 == false){   // in case SML data is plausible (i.e., SML header is OK and also no buffer overflow) it still happens that eHZ reading is derived from this data. Examining this showed that in those cases typically less than 397 bytes SML data were read. This while loop/condition should prevent this.
    getSMLData(mySerial_2, eHZ2_ID);                          // get SML data from 2nd electricity meter (Input: A1), store it into (global) buffer
  }
  createTimeStamp(eHZ2_ID);
  Serial.println("Time stamp eHZ_2 created...");
  eHZ_2_Reading = getElectricityMeterReading(buffer);     // extract OBIS 1.8.0. in Wh x 10 and store it in (global) variable 
  Serial.print("eHZ_2 Reading: ");
  Serial.println(eHZ_2_Reading);

  Serial.println();
  
  // turn ON red LED to show that writing is beeing performed and SD card should NOT be removed. Prewarn by blinking for about 3s.
  for(byte i=0; i<3; i++) {
    digitalWrite(LED_WriteWarning, HIGH);
    delay(500);
    digitalWrite(LED_WriteWarning, LOW);
    delay(500);
  }
  digitalWrite(LED_WriteWarning, HIGH);
  // write data to file (time + 2 readings)
  writeTimeAndReadingToFile();
  // turn OFF red LED to show that writing is FINISHED and SD card CAN be removed
  digitalWrite(LED_WriteWarning, LOW);
  delay(1000);
   
  // set blinking behaviour of LED depending on result of SML data acquisition of eHZ1
  if(SML_DataAcquisition_eHZ1 == true) {
     eHZ1Blink_ON = 1000;
  }
  if(SML_DataAcquisition_eHZ1 == false) {
    eHZ1Blink_ON = 250;
  }
  // set blinking behaviour of LED depending on result of SML data acquisition of eHZ1
  if(SML_DataAcquisition_eHZ2 == true) {
    eHZ2Blink_ON = 1000;
  }
  if(SML_DataAcquisition_eHZ2 == false) {
    eHZ2Blink_ON = 250;
  }

  startTime = millis();
  // show result of data acquisition by blinking slow (success) or fast (fail). slow/fast defined above.
  while(millis()-startTime < loggingInterval){
    for(int i=0; i<3; i++) {
      digitalWrite(LED_SML_Acquisition_eHZ1, HIGH);
      delay(eHZ1Blink_ON);
      digitalWrite(LED_SML_Acquisition_eHZ1, LOW);
      delay(eHZ1Blink_OFF);
    }
    for(int i=0; i<3; i++) {
      digitalWrite(LED_SML_Acquisition_eHZ2, HIGH);
      delay(eHZ2Blink_ON);
      digitalWrite(LED_SML_Acquisition_eHZ2, LOW);
      delay(eHZ2Blink_OFF);
    }              
  }

}
IR-Diode-Schaltung_Test_NanoEvery.inoArduino
Short Arduino sketch used to optimize position of receiving IR phototransistor in front of eHZ's IR sender diode.
// A0: amplified signal of 1st IR diode (output=collector of 1st transistor)
// A1: amplified signal of 2nd IR diode (output=collector of 2nd transistor) (in case 2 IR diodes fo 2 eHZs used)
// A6: raw signal of 1st IR photo diode (base of 1st transistor)
// A7: raw signal of 2nd IR photo diode (base of 2nd transistor) (in case 2 IR diodes fo 2 eHZs used) 


void setup() {
  
  //for 1st IR diode  
  pinMode(A0, INPUT);
  pinMode(A6, INPUT);
  
  //for 2nd IR diode
  pinMode(A1, INPUT);
  pinMode(A7, INPUT);
  Serial.begin(9600);  
}

void loop() {
  //for 1st IR diode

  Serial.print("A0: ");
  Serial.print(analogRead(A0));
  Serial.print(" ;  A6: ");
  Serial.print(analogRead(A6));


  //for 2nd IR diode
  Serial.print(" ; A1: ");
  Serial.print(analogRead(A1));
  Serial.print(" ;  A7: ");
  Serial.println(analogRead(A7));


}

Schematics

Schematics for reading to smart meters using Arduino Nano Every
2ehz auslesen schaltplan nano every v02 schaltplan 8nklkmnomj
Schematics for reading to smart meters using Arduino Nano Every

Comments

Author

Default
torstengeppert
  • 2 projects
  • 1 follower

Additional contributors

Published on

April 8, 2020

Members who respect this project

Auziqni

and 1 other

See similar projects
you might like

Similar projects you might like

Bluetooth Mobile Remote Lamp with Weather Station

Project tutorial by Kutluhan Aktar

  • 2,208 views
  • 1 comment
  • 3 respects

Smart Lock Door with Voice Activation Using Arduino Uno

Project showcase by bangkitwahyu

  • 3,143 views
  • 2 comments
  • 19 respects

RFID Based Smart Attendance System

Project showcase by team_chkr

  • 4,101 views
  • 1 comment
  • 13 respects

Smart Home - Smart Rules using ARTIK Cloud & Photon

Project tutorial by Raghavendra Ponuganti

  • 5,407 views
  • 3 comments
  • 17 respects

Smart Soft Switch

Project tutorial by Vishwas Navada

  • 1,350 views
  • 0 comments
  • 4 respects

Smart Battery Charger Multiplexer with Smart Display

Project tutorial by leonzak

  • 6,402 views
  • 8 comments
  • 21 respects
Add projectSign up / Login